12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655 |
- /* vim: tabstop=4 shiftwidth=4 noexpandtab
- * This file is part of ToaruOS and is released under the terms
- * of the NCSA / University of Illinois License - see LICENSE.md
- * Copyright (C) 2014-2018 K. Lange
- */
- #include <kernel/module.h>
- #include <kernel/logging.h>
- #include <kernel/ipv4.h>
- #include <kernel/printf.h>
- #include <kernel/tokenize.h>
- #include <kernel/mod/net.h>
- #include <kernel/mod/procfs.h>
- #include <toaru/list.h>
- #include <toaru/hashmap.h>
- static hashmap_t * dns_cache;
- static list_t * dns_waiters = NULL;
- static uint32_t _dns_server;
- static hashmap_t *_tcp_sockets = NULL;
- static hashmap_t *_udp_sockets = NULL;
- static void parse_dns_response(fs_node_t * tty, void * last_packet);
- static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries);
- size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip);
- static size_t write_arp_request(uint8_t * buffer, uint32_t ip);
- static uint8_t _gateway[6] = {255,255,255,255,255,255};
- static struct netif _netif = {0};
- static int tasklet_pid = 0;
- uint32_t get_primary_dns(void);
- static uint32_t netif_func(fs_node_t *node, uint32_t offset, uint32_t size, uint8_t *buffer) {
- char * buf = malloc(4096);
- struct netif * netif = &_netif;
- char ip[16];
- ip_ntoa(netif->source, ip);
- char dns[16];
- ip_ntoa(get_primary_dns(), dns);
- char gw[16];
- ip_ntoa(netif->gateway, gw);
- if (netif->hwaddr[0] == 0 &&
- netif->hwaddr[1] == 0 &&
- netif->hwaddr[2] == 0 &&
- netif->hwaddr[3] == 0 &&
- netif->hwaddr[4] == 0 &&
- netif->hwaddr[5] == 0) {
- sprintf(buf, "no network\n");
- } else {
- sprintf(buf,
- "ip:\t%s\n"
- "mac:\t%2x:%2x:%2x:%2x:%2x:%2x\n"
- "device:\t%s\n"
- "dns:\t%s\n"
- "gateway:\t%s\n"
- ,
- ip,
- netif->hwaddr[0], netif->hwaddr[1], netif->hwaddr[2], netif->hwaddr[3], netif->hwaddr[4], netif->hwaddr[5],
- netif->driver,
- dns,
- gw
- );
- }
- size_t _bsize = strlen(buf);
- if (offset > _bsize) {
- free(buf);
- return 0;
- }
- if (size > _bsize - offset) size = _bsize - offset;
- memcpy(buffer, buf + offset, size);
- free(buf);
- return size;
- }
- static struct procfs_entry netif_entry = {
- 0, /* filled by install */
- "netif",
- netif_func,
- };
- void init_netif_funcs(get_mac_func mac_func, get_packet_func get_func, send_packet_func send_func, char * device) {
- _netif.get_mac = mac_func;
- _netif.get_packet = get_func;
- _netif.send_packet = send_func;
- _netif.driver = device;
- memcpy(_netif.hwaddr, _netif.get_mac(), sizeof(_netif.hwaddr));
- if (!netif_entry.id) {
- int (*procfs_install)(struct procfs_entry *) = (int (*)(struct procfs_entry *))(uintptr_t)hashmap_get(modules_get_symbols(),"procfs_install");
- if (procfs_install) {
- procfs_install(&netif_entry);
- }
- }
- if (!tasklet_pid) {
- tasklet_pid = create_kernel_tasklet(net_handler, "[net]", NULL);
- debug_print(NOTICE, "Network worker tasklet started with pid %d", tasklet_pid);
- }
- }
- struct netif * get_default_network_interface(void) {
- return &_netif;
- }
- uint32_t get_primary_dns(void) {
- return _dns_server;
- }
- 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 *)lfind(c, '.');
- *i = '\0';
- out[0] = atoi(c);
- c += strlen(c) + 1;
- i = (char *)lfind(c, '.');
- *i = '\0';
- out[1] = atoi(c);
- c += strlen(c) + 1;
- i = (char *)lfind(c, '.');
- *i = '\0';
- out[2] = atoi(c);
- c += strlen(c) + 1;
- out[3] = atoi(c);
- return ((out[0] << 24) | (out[1] << 16) | (out[2] << 8) | (out[3]));
- }
- void ip_ntoa(uint32_t src_addr, char * out) {
- sprintf(out, "%d.%d.%d.%d",
- (src_addr & 0xFF000000) >> 24,
- (src_addr & 0xFF0000) >> 16,
- (src_addr & 0xFF00) >> 8,
- (src_addr & 0xFF));
- }
- uint16_t calculate_ipv4_checksum(struct ipv4_packet * p) {
- uint32_t sum = 0;
- uint16_t * s = (uint16_t *)p;
- /* TODO: Checksums for options? */
- for (int i = 0; i < 10; ++i) {
- sum += ntohs(s[i]);
- }
- if (sum > 0xFFFF) {
- sum = (sum >> 16) + (sum & 0xFFFF);
- }
- return ~(sum & 0xFFFF) & 0xFFFF;
- }
- uint16_t calculate_tcp_checksum(struct tcp_check_header * p, struct tcp_header * h, void * d, size_t payload_size) {
- uint32_t sum = 0;
- uint16_t * s = (uint16_t *)p;
- /* TODO: Checksums for options? */
- for (int i = 0; i < 6; ++i) {
- sum += ntohs(s[i]);
- if (sum > 0xFFFF) {
- sum = (sum >> 16) + (sum & 0xFFFF);
- }
- }
- s = (uint16_t *)h;
- for (int i = 0; i < 10; ++i) {
- sum += ntohs(s[i]);
- if (sum > 0xFFFF) {
- sum = (sum >> 16) + (sum & 0xFFFF);
- }
- }
- uint16_t d_words = payload_size / 2;
- s = (uint16_t *)d;
- for (unsigned int i = 0; i < d_words; ++i) {
- sum += ntohs(s[i]);
- if (sum > 0xFFFF) {
- sum = (sum >> 16) + (sum & 0xFFFF);
- }
- }
- if (d_words * 2 != payload_size) {
- uint8_t * t = (uint8_t *)d;
- uint8_t tmp[2];
- tmp[0] = t[d_words * sizeof(uint16_t)];
- tmp[1] = 0;
- uint16_t * f = (uint16_t *)tmp;
- sum += ntohs(f[0]);
- if (sum > 0xFFFF) {
- sum = (sum >> 16) + (sum & 0xFFFF);
- }
- }
- return ~(sum & 0xFFFF) & 0xFFFF;
- }
- static struct dirent * readdir_netfs(fs_node_t *node, uint32_t index) {
- if (index == 0) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, ".");
- return out;
- }
- if (index == 1) {
- struct dirent * out = malloc(sizeof(struct dirent));
- memset(out, 0x00, sizeof(struct dirent));
- out->ino = 0;
- strcpy(out->name, "..");
- return out;
- }
- index -= 2;
- return NULL;
- }
- size_t dns_name_to_normal_name(struct dns_packet * dns, size_t offset, char * buf) {
- uint8_t * bytes = (uint8_t *)dns;
- size_t i = 0;
- while (1) {
- uint8_t c = bytes[offset];
- if (c == 0) break;
- if (c >= 0xC0) {
- uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1];
- i += dns_name_to_normal_name(dns, ref, &buf[i]);
- return i;
- }
- offset++;
- for (size_t j = 0; j < c; j++) {
- buf[i] = bytes[offset];
- i++;
- offset++;
- }
- buf[i] = '.';
- i++;
- buf[i] = '\0';
- }
- if (i == 0) return 0;
- buf[i-1] = '\0';
- return i-1;
- }
- size_t get_dns_name(char * buffer, struct dns_packet * dns, size_t offset) {
- uint8_t * bytes = (uint8_t *)dns;
- while (1) {
- uint8_t c = bytes[offset];
- if (c == 0) {
- offset++;
- return offset;
- } else if (c >= 0xC0) {
- uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1];
- get_dns_name(buffer, dns, ref);
- offset++;
- offset++;
- return offset;
- } else {
- for (int i = 0; i < c; ++i) {
- *buffer = bytes[offset+1+i];
- buffer++;
- *buffer = '\0';
- }
- *buffer = '.';
- buffer++;
- *buffer = '\0';
- offset += c + 1;
- }
- }
- }
- size_t print_dns_name(fs_node_t * tty, struct dns_packet * dns, size_t offset) {
- uint8_t * bytes = (uint8_t *)dns;
- while (1) {
- uint8_t c = bytes[offset];
- if (c == 0) {
- offset++;
- return offset;
- } else if (c >= 0xC0) {
- uint16_t ref = ((c - 0xC0) << 8) + bytes[offset+1];
- print_dns_name(tty, dns, ref);
- offset++;
- offset++;
- return offset;
- } else {
- for (int i = 0; i < c; ++i) {
- fprintf(tty,"%c",bytes[offset+1+i]);
- }
- fprintf(tty,".");
- offset += c + 1;
- }
- }
- }
- static int is_ip(char * name) {
- unsigned int dot_count = 0;
- unsigned int t = 0;
- for (char * c = name; *c != '\0'; ++c) {
- if ((*c < '0' || *c > '9') && (*c != '.')) return 0;
- if (*c == '.') {
- if (t > 255) return 0;
- dot_count++;
- t = 0;
- } else {
- t *= 10;
- t += *c - '0';
- }
- if (dot_count == 4) return 0;
- }
- if (dot_count != 3) return 0;
- return 1;
- }
- static char read_a_byte(struct socket * stream, int * status) {
- static char * foo = NULL;
- static char * read_ptr = NULL;
- static int have_bytes = 0;
- if (!foo) foo = malloc(4096);
- while (!have_bytes) {
- memset(foo, 0x00, 4096);
- have_bytes = net_recv(stream, (uint8_t *)foo, 4096);
- if (have_bytes == 0) {
- *status = 1;
- return 0;
- }
- debug_print(WARNING, "Received %d bytes...", have_bytes);
- read_ptr = foo;
- }
- char ret = *read_ptr;
- have_bytes -= 1;
- read_ptr++;
- return ret;
- }
- static char * fgets(char * buf, int size, struct socket * stream) {
- char * x = buf;
- int collected = 0;
- while (collected < size) {
- int status = 0;
- *x = read_a_byte(stream, &status);
- if (status == 1) {
- return buf;
- }
- collected++;
- if (*x == '\n') break;
- x++;
- }
- x++;
- *x = '\0';
- return buf;
- }
- static void socket_alert_waiters(struct socket * sock) {
- if (sock->alert_waiters) {
- while (sock->alert_waiters->head) {
- node_t * node = list_dequeue(sock->alert_waiters);
- process_t * p = node->value;
- process_alert_node(p, sock);
- free(node);
- }
- }
- }
- static int socket_check(fs_node_t * node) {
- struct socket * sock = node->device;
- if (sock->bytes_available) {
- return 0;
- }
- if (sock->packet_queue->length > 0) {
- return 0;
- }
- return 1;
- }
- static int socket_wait(fs_node_t * node, void * process) {
- struct socket * sock = node->device;
- if (!list_find(sock->alert_waiters, process)) {
- list_insert(sock->alert_waiters, process);
- }
- list_insert(((process_t *)process)->node_waits, sock);
- return 0;
- }
- static uint32_t socket_read(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
- /* Sleep until we have something to receive */
- #if 0
- fgets((char *)buffer, size, node->device);
- return strlen((char *)buffer);
- #else
- return net_recv(node->device, buffer, size);
- #endif
- }
- static uint32_t socket_write(fs_node_t * node, uint32_t offset, uint32_t size, uint8_t * buffer) {
- /* Add the packet to the appropriate interface queue and send it off. */
- net_send((struct socket *)node->device, buffer, size, 0);
- return size;
- }
- uint16_t next_ephemeral_port(void) {
- static uint16_t next = 49152;
- if (next == 0) {
- assert(0 && "All out of ephemeral ports, halting this time.");
- }
- uint16_t out = next;
- next++;
- if (next == 0) {
- debug_print(WARNING, "Ran out of ephemeral ports - next time I'm going to bail.");
- debug_print(WARNING, "You really need to implement a bitmap here.");
- }
- return out;
- }
- fs_node_t * socket_ipv4_tcp_create(uint32_t dest, uint16_t target_port, uint16_t source_port) {
- /* Okay, first step is to get us added to the table so we can receive syns. */
- return NULL;
- }
- static int gethost(char * name, uint32_t * ip) {
- if (is_ip(name)) {
- debug_print(WARNING, " IP: %x", ip_aton(name));
- *ip = ip_aton(name);
- return 0;
- } else {
- if (hashmap_has(dns_cache, name)) {
- *ip = ip_aton(hashmap_get(dns_cache, name));
- debug_print(WARNING, " In Cache: %s → %x", name, ip);
- return 0;
- } else {
- debug_print(WARNING, " Not in cache: %s", name);
- debug_print(WARNING, " Still needs look up.");
- char * xname = strdup(name);
- char * queries = malloc(1024);
- queries[0] = '\0';
- char * subs[10]; /* 10 is probably not the best number. */
- int argc = tokenize(xname, ".", subs);
- int n = 0;
- for (int i = 0; i < argc; ++i) {
- debug_print(WARNING, "dns [%d]%s", strlen(subs[i]), subs[i]);
- sprintf(&queries[n], "%c%s", strlen(subs[i]), subs[i]);
- n += strlen(&queries[n]);
- }
- int c = strlen(queries) + 1;
- queries[c+0] = 0x00;
- queries[c+1] = 0x01; /* A */
- queries[c+2] = 0x00;
- queries[c+3] = 0x01; /* IN */
- free(xname);
- debug_print(WARNING, "Querying...");
- void * tmp = malloc(1024);
- size_t packet_size = write_dns_packet(tmp, c + 4, (uint8_t *)queries);
- free(queries);
- _netif.send_packet(tmp, packet_size);
- free(tmp);
- /* wait for response */
- if (current_process->id != tasklet_pid) {
- sleep_on(dns_waiters);
- }
- if (hashmap_has(dns_cache, name)) {
- *ip = ip_aton(hashmap_get(dns_cache, name));
- debug_print(WARNING, " Now in cache: %s → %x", name, ip);
- return 0;
- } else {
- if (current_process->id == tasklet_pid) {
- debug_print(WARNING, "Query hasn't returned yet, but we're in the network thread, so we need to yield.");
- return 2;
- }
- gethost(name,ip);
- return 1;
- }
- }
- }
- }
- /* TODO: socket_close - TCP close; UDP... just clean us up */
- /* TODO: socket_open - idk, whatever */
- static fs_node_t * finddir_netfs(fs_node_t * node, char * name) {
- /* Should essentially find anything. */
- debug_print(WARNING, "Need to look up domain or check if is IP: %s", name);
- /* Block until lookup is complete */
- int port = 80;
- char * colon;
- if ((colon = strstr(name, ":"))) {
- /* Port numbers */
- *colon = '\0';
- colon++;
- port = atoi(colon);
- }
- uint32_t ip = 0;
- if (gethost(name, &ip)) return NULL;
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, name);
- fnode->mask = 0666;
- fnode->flags = FS_CHARDEVICE;
- fnode->read = socket_read;
- fnode->write = socket_write;
- fnode->device = (void *)net_open(SOCK_STREAM);
- fnode->selectcheck = socket_check;
- fnode->selectwait = socket_wait;
- net_connect((struct socket *)fnode->device, ip, port);
- return fnode;
- }
- static int ioctl_netfs(fs_node_t * node, int request, void * argp) {
- switch (request) {
- case 0x5000: {
- /* */
- debug_print(INFO, "DNS query from userspace");
- void ** x = (void **)argp;
- char * host = x[0];
- uint32_t * ip = x[1];
- /* TODO: Validate */
- return gethost(host, ip);
- }
- }
- return 0;
- }
- static size_t write_dns_packet(uint8_t * buffer, size_t queries_len, uint8_t * queries) {
- size_t offset = 0;
- size_t payload_size = sizeof(struct dns_packet) + queries_len;
- /* Then, let's write an ethernet frame */
- struct ethernet_packet eth_out = {
- .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .destination = BROADCAST_MAC,
- .type = htons(0x0800),
- };
- memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet));
- offset += sizeof(struct ethernet_packet);
- /* Prepare the IPv4 header */
- uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size);
- uint16_t _ident = htons(1);
- struct ipv4_packet ipv4_out = {
- .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */
- .dscp_ecn = 0, /* not setting either of those */
- .length = _length,
- .ident = _ident,
- .flags_fragment = 0,
- .ttl = 0x40,
- .protocol = IPV4_PROT_UDP,
- .checksum = 0, /* fill this in later */
- .source = htonl(_netif.source),
- .destination = htonl(_dns_server),
- };
- uint16_t checksum = calculate_ipv4_checksum(&ipv4_out);
- ipv4_out.checksum = htons(checksum);
- memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet));
- offset += sizeof(struct ipv4_packet);
- uint16_t _udp_source = htons(50053); /* Use an ephemeral port */
- uint16_t _udp_destination = htons(53);
- uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size);
- /* Now let's build a UDP packet */
- struct udp_packet udp_out = {
- .source_port = _udp_source,
- .destination_port = _udp_destination,
- .length = _udp_length,
- .checksum = 0,
- };
- /* XXX calculate checksum here */
- memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet));
- offset += sizeof(struct udp_packet);
- /* DNS header */
- struct dns_packet dns_out = {
- .qid = htons(0),
- .flags = htons(0x0100), /* Standard query */
- .questions = htons(1), /* 1 question */
- .answers = htons(0),
- .authorities = htons(0),
- .additional = htons(0),
- };
- memcpy(&buffer[offset], &dns_out, sizeof(struct dns_packet));
- offset += sizeof(struct dns_packet);
- memcpy(&buffer[offset], queries, queries_len);
- offset += queries_len;
- return offset;
- }
- static int net_send_ether(struct socket *socket, struct netif* netif, uint16_t ether_type, void* payload, uint32_t payload_size) {
- struct ethernet_packet *eth = malloc(sizeof(struct ethernet_packet) + payload_size);
- memcpy(eth->source, netif->hwaddr, sizeof(eth->source));
- //memset(eth->destination, 0xFF, sizeof(eth->destination));
- memcpy(eth->destination, _gateway, sizeof(_gateway));
- eth->type = htons(ether_type);
- if (payload_size) {
- memcpy(eth->payload, payload, payload_size);
- }
- netif->send_packet((uint8_t*)eth, sizeof(struct ethernet_packet) + payload_size);
- free(eth);
- return 1; // yolo
- }
- static int net_send_ip(struct socket *socket, int proto, void* payload, uint32_t payload_size) {
- struct ipv4_packet *ipv4 = malloc(sizeof(struct ipv4_packet) + payload_size);
- uint16_t _length = htons(sizeof(struct ipv4_packet) + payload_size);
- uint16_t _ident = htons(1);
- ipv4->version_ihl = ((0x4 << 4) | (0x5 << 0)); /* 4 = ipv4, 5 = no options */
- ipv4->dscp_ecn = 0; /* not setting either of those */
- ipv4->length = _length;
- ipv4->ident = _ident;
- ipv4->flags_fragment = 0;
- ipv4->ttl = 0x40;
- ipv4->protocol = proto;
- ipv4->checksum = 0; // Fill in later */
- ipv4->source = htonl(_netif.source),
- ipv4->destination = htonl(socket->ip);
- uint16_t checksum = calculate_ipv4_checksum(ipv4);
- ipv4->checksum = htons(checksum);
- if (proto == IPV4_PROT_TCP) {
- // Need to calculate TCP checksum
- struct tcp_check_header check_hd = {
- .source = ipv4->source,
- .destination = ipv4->destination,
- .zeros = 0,
- .protocol = 6,
- .tcp_len = htons(payload_size),
- };
- // debug_print(WARNING, "net_send_ip: Payload size: %d\n", payload_size);
- struct tcp_header* tcp_hdr = (struct tcp_header*)payload;
- // debug_print(WARNING, "net_send_ip: Header len htons: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp_hdr));
- size_t orig_payload_size = payload_size - TCP_HEADER_LENGTH_FLIPPED(tcp_hdr);
- uint16_t chk = calculate_tcp_checksum(&check_hd, tcp_hdr, tcp_hdr->payload, orig_payload_size);
- tcp_hdr->checksum = htons(chk);
- }
- if (payload) {
- memcpy(ipv4->payload, payload, payload_size);
- free(payload);
- }
- // TODO: netif should not be a global thing. But the route should be looked up here and a netif object created/returned
- int out = net_send_ether(socket, &_netif, ETHERNET_TYPE_IPV4, ipv4, sizeof(struct ipv4_packet) + payload_size);
- free(ipv4);
- return out;
- }
- static int net_send_tcp(struct socket *socket, uint16_t flags, uint8_t * payload, uint32_t payload_size) {
- struct tcp_header *tcp = malloc(sizeof(struct tcp_header) + payload_size);
- tcp->source_port = htons(socket->port_recv);
- tcp->destination_port = htons(socket->port_dest);
- tcp->seq_number = htonl(socket->proto_sock.tcp_socket.seq_no);
- tcp->ack_number = flags & (TCP_FLAGS_ACK) ? htonl(socket->proto_sock.tcp_socket.ack_no) : 0;
- tcp->flags = htons(0x5000 ^ (flags & 0xFF));
- tcp->window_size = htons(1548-54);
- tcp->checksum = 0; // Fill in later
- tcp->urgent = 0;
- if ((flags & 0xff) == TCP_FLAGS_SYN) {
- // If only SYN set, expected ACK will be 1 despite no payload
- socket->proto_sock.tcp_socket.seq_no += 1;
- } else {
- socket->proto_sock.tcp_socket.seq_no += payload_size;
- }
- if (payload) {
- memcpy(tcp->payload, payload, payload_size);
- }
- return net_send_ip(socket, IPV4_PROT_TCP, tcp, sizeof(struct tcp_header) + payload_size);
- }
- struct socket* net_open(uint32_t type) {
- // This is a socket() call
- struct socket *sock = malloc(sizeof(struct socket));
- memset(sock, 0, sizeof(struct socket));
- sock->sock_type = type;
- return sock;
- }
- int net_close(struct socket* socket) {
- // socket->is_connected;
- socket->status = 1; /* Disconnected */
- wakeup_queue(socket->packet_wait);
- socket_alert_waiters(socket);
- return 1;
- }
- int net_send(struct socket* socket, uint8_t* payload, size_t payload_size, int flags) {
- return net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_PSH, payload, payload_size);
- }
- size_t net_recv(struct socket* socket, uint8_t* buffer, size_t len) {
- tcpdata_t *tcpdata = NULL;
- node_t *node = NULL;
- debug_print(INFO, "0x%x [socket]", socket);
- size_t offset = 0;
- size_t size_to_read = 0;
- do {
- if (socket->bytes_available) {
- tcpdata = socket->current_packet;
- } else {
- spin_lock(socket->packet_queue_lock);
- do {
- if (socket->packet_queue->length > 0) {
- node = list_dequeue(socket->packet_queue);
- spin_unlock(socket->packet_queue_lock);
- break;
- } else {
- if (socket->status == 1) {
- spin_unlock(socket->packet_queue_lock);
- debug_print(WARNING, "Socket closed, done reading.");
- return 0;
- }
- spin_unlock(socket->packet_queue_lock);
- sleep_on(socket->packet_wait);
- spin_lock(socket->packet_queue_lock);
- }
- } while (1);
- tcpdata = node->value;
- socket->bytes_available = tcpdata->payload_size;
- socket->bytes_read = 0;
- free(node);
- }
- size_to_read = MIN(len, socket->bytes_available);
- if (tcpdata->payload != 0) {
- memcpy(buffer + offset, tcpdata->payload + socket->bytes_read, size_to_read);
- }
- offset += size_to_read;
- if (size_to_read < socket->bytes_available) {
- socket->bytes_available -= size_to_read;
- socket->bytes_read += size_to_read;
- socket->current_packet = tcpdata;
- } else {
- socket->bytes_available = 0;
- socket->current_packet = NULL;
- free(tcpdata->payload);
- free(tcpdata);
- }
- } while (!size_to_read);
- return size_to_read;
- }
- static void net_handle_tcp(struct tcp_header * tcp, size_t length) {
- size_t data_length = length - TCP_HEADER_LENGTH_FLIPPED(tcp);
- /* Find socket */
- if (hashmap_has(_tcp_sockets, (void *)ntohs(tcp->destination_port))) {
- struct socket *socket = hashmap_get(_tcp_sockets, (void *)ntohs(tcp->destination_port));
- if (socket->status == 1) {
- debug_print(ERROR, "Socket is closed, but still receiving packets. Should send FIN. socket=0x%x", socket);
- return;
- }
- if (socket->proto_sock.tcp_socket.seq_no != ntohl(tcp->ack_number)) {
- // Drop packet
- debug_print(WARNING, "Dropping packet. Expected ack: %d | Got ack: %d",
- socket->proto_sock.tcp_socket.seq_no, ntohl(tcp->ack_number));
- return;
- }
- if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK)) {
- socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1;
- net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0);
- wakeup_queue(socket->proto_sock.tcp_socket.is_connected);
- } else if (htons(tcp->flags) & TCP_FLAGS_RES) {
- /* Reset doesn't necessarily mean close. */
- debug_print(WARNING, "net_handle_tcp: Received RST - socket closing");
- net_close(socket);
- return;
- } else {
- // Store a copy of the layer 5 data for a userspace recv() call
- tcpdata_t *tcpdata = malloc(sizeof(tcpdata_t));
- tcpdata->payload_size = length - TCP_HEADER_LENGTH_FLIPPED(tcp);
- if (tcpdata->payload_size == 0) {
- if (htons(tcp->flags) & TCP_FLAGS_FIN) {
- /* We should make sure we finish sending before closing. */
- debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK");
- socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1;
- net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0);
- wakeup_queue(socket->proto_sock.tcp_socket.is_connected);
- net_close(socket);
- }
- free(tcpdata);
- return;
- }
- // debug_print(WARNING, "net_handle_tcp: payload length: %d\n", length);
- // debug_print(WARNING, "net_handle_tcp: flipped tcp flags hdr len: %d\n", TCP_HEADER_LENGTH_FLIPPED(tcp));
- // debug_print(WARNING, "net_handle_tcp: tcpdata->payload_size: %d\n", tcpdata->payload_size);
- if (tcpdata->payload_size > 0) {
- tcpdata->payload = malloc(tcpdata->payload_size);
- memcpy(tcpdata->payload, tcp->payload, tcpdata->payload_size);
- } else {
- tcpdata->payload = NULL;
- }
- socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length;
- if ((htons(tcp->flags) & TCP_FLAGS_SYN) && (htons(tcp->flags) & TCP_FLAGS_ACK) && data_length == 0) {
- socket->proto_sock.tcp_socket.ack_no += 1;
- }
- socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + tcpdata->payload_size;
- spin_lock(socket->packet_queue_lock);
- list_insert(socket->packet_queue, tcpdata);
- spin_unlock(socket->packet_queue_lock);
- // Send acknowledgement of receiving data
- net_send_tcp(socket, TCP_FLAGS_ACK, NULL, 0);
- wakeup_queue(socket->packet_wait);
- socket_alert_waiters(socket);
- if (htons(tcp->flags) & TCP_FLAGS_FIN) {
- /* We should make sure we finish sending before closing. */
- debug_print(WARNING, "net_handle_tcp: Received FIN - socket closing with SYNACK");
- socket->proto_sock.tcp_socket.ack_no = ntohl(tcp->seq_number) + data_length + 1;
- net_send_tcp(socket, TCP_FLAGS_ACK | TCP_FLAGS_FIN, NULL, 0);
- wakeup_queue(socket->proto_sock.tcp_socket.is_connected);
- net_close(socket);
- }
- }
- } else {
- debug_print(WARNING, "net_handle_tcp: Received packet not associated with a socket!");
- }
- }
- static void net_handle_udp(struct udp_packet * udp, size_t length) {
- // size_t data_length = length - sizeof(struct tcp_header);
- debug_print(WARNING, "UDP response!");
- /* Short-circuit DNS */
- if (ntohs(udp->source_port) == 53) {
- debug_print(WARNING, "UDP response to DNS query!");
- parse_dns_response(debug_file, udp);
- return;
- }
- if (ntohs(udp->source_port) == 67) {
- debug_print(WARNING, "UDP response to DHCP!");
- {
- void * tmp = malloc(1024);
- size_t packet_size = write_arp_request(tmp, _netif.gateway);
- _netif.send_packet(tmp, packet_size);
- free(tmp);
- }
- return;
- }
- /* Find socket */
- if (hashmap_has(_udp_sockets, (void *)ntohs(udp->source_port))) {
- /* Do the thing */
- } else {
- /* ??? */
- }
- }
- static void net_handle_ipv4(struct ipv4_packet * ipv4) {
- debug_print(INFO, "net_handle_ipv4: ENTER");
- switch (ipv4->protocol) {
- case IPV4_PROT_TCP:
- net_handle_tcp((struct tcp_header *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet));
- break;
- case IPV4_PROT_UDP:
- net_handle_udp((struct udp_packet *)ipv4->payload, ntohs(ipv4->length) - sizeof(struct ipv4_packet));
- break;
- default:
- /* XXX */
- break;
- }
- }
- static struct ethernet_packet* net_receive(void) {
- struct ethernet_packet *eth = _netif.get_packet();
- return eth;
- }
- int net_connect(struct socket* socket, uint32_t dest_ip, uint16_t dest_port) {
- if (socket->sock_type == SOCK_DGRAM) {
- // Can't connect UDP
- return -1;
- }
- memset(socket->mac, 0, sizeof(socket->mac)); // idk
- socket->port_recv = next_ephemeral_port();
- socket->proto_sock.tcp_socket.is_connected = list_create();
- socket->proto_sock.tcp_socket.seq_no = 0;
- socket->proto_sock.tcp_socket.ack_no = 0;
- socket->proto_sock.tcp_socket.status = 0;
- socket->packet_queue = list_create();
- socket->packet_wait = list_create();
- socket->alert_waiters = list_create();
- socket->ip = dest_ip; //ip_aton("10.255.50.206");
- socket->port_dest = dest_port; //12345;
- debug_print(WARNING, "net_connect: using ephemeral port: %d", (void*)socket->port_recv);
- hashmap_set(_tcp_sockets, (void*)socket->port_recv, socket);
- net_send_tcp(socket, TCP_FLAGS_SYN, NULL, 0);
- // debug_print(WARNING, "net_connect:sent tcp SYN: %d", ret);
- // Race condition here - if net_handle_tcp runs and connects before this sleep
- sleep_on(socket->proto_sock.tcp_socket.is_connected);
- return 1;
- }
- static void placeholder_dhcp(void) {
- debug_print(NOTICE, "Sending DHCP discover");
- void * tmp = malloc(1024);
- size_t packet_size = write_dhcp_packet(tmp);
- _netif.send_packet(tmp, packet_size);
- free(tmp);
- while (1) {
- struct ethernet_packet * eth = (struct ethernet_packet *)_netif.get_packet();
- uint16_t eth_type = ntohs(eth->type);
- debug_print(NOTICE, "Ethernet II, Src: (%2x:%2x:%2x:%2x:%2x:%2x), Dst: (%2x:%2x:%2x:%2x:%2x:%2x) [type=%4x])",
- eth->source[0], eth->source[1], eth->source[2],
- eth->source[3], eth->source[4], eth->source[5],
- eth->destination[0], eth->destination[1], eth->destination[2],
- eth->destination[3], eth->destination[4], eth->destination[5],
- eth_type);
- if (eth_type != 0x0800) {
- debug_print(WARNING, "ARP packet while waiting for DHCP...");
- free(eth);
- continue;
- }
- struct ipv4_packet * ipv4 = (struct ipv4_packet *)eth->payload;
- uint32_t src_addr = ntohl(ipv4->source);
- uint32_t dst_addr = ntohl(ipv4->destination);
- uint16_t length = ntohs(ipv4->length);
- char src_ip[16];
- char dst_ip[16];
- ip_ntoa(src_addr, src_ip);
- ip_ntoa(dst_addr, dst_ip);
- debug_print(NOTICE, "IP packet [%s → %s] length=%d bytes",
- src_ip, dst_ip, length);
- if (ipv4->protocol != IPV4_PROT_UDP) {
- debug_print(WARNING, "Protocol: %d", ipv4->protocol);
- debug_print(WARNING, "Bad packet...");
- free(eth);
- continue;
- }
- struct udp_packet * udp = (struct udp_packet *)ipv4->payload;;
- uint16_t src_port = ntohs(udp->source_port);
- uint16_t dst_port = ntohs(udp->destination_port);
- uint16_t udp_len = ntohs(udp->length);
- debug_print(NOTICE, "UDP [%d → %d] length=%d bytes",
- src_port, dst_port, udp_len);
- if (dst_port != 68) {
- debug_print(WARNING, "Destination port: %d", dst_port);
- debug_print(WARNING, "Bad packet...");
- free(eth);
- continue;
- }
- struct dhcp_packet * dhcp = (struct dhcp_packet *)udp->payload;
- uint32_t yiaddr = ntohl(dhcp->yiaddr);
- char yiaddr_ip[16];
- ip_ntoa(yiaddr, yiaddr_ip);
- debug_print(NOTICE, "DHCP Offer: %s", yiaddr_ip);
- _netif.source = yiaddr;
- debug_print(NOTICE," Scanning offer for DNS servers...");
- size_t i = sizeof(struct dhcp_packet);
- size_t j = 0;
- while (i < length) {
- uint8_t type = dhcp->options[j];
- uint8_t len = dhcp->options[j+1];
- uint8_t * data = &dhcp->options[j+2];
- debug_print(NOTICE," type=%d, len=%d", type, len);
- if (type == 255) {
- break;
- } else if (type == 6) {
- /* DNS Server! */
- uint32_t dnsaddr = ntohl(*(uint32_t *)data);
- char ip[16];
- ip_ntoa(dnsaddr, ip);
- debug_print(NOTICE, "Found one: %s", ip);
- _dns_server = dnsaddr;
- } else if (type == 3) {
- _netif.gateway = ntohl(*(uint32_t *)data);
- }
- j += 2 + len;
- i += 2 + len;
- }
- debug_print(NOTICE, "Sending DHCP Request...");
- void * tmp = malloc(1024);
- size_t packet_size = write_dhcp_request(tmp, (uint8_t *)&dhcp->yiaddr);
- _netif.send_packet(tmp, packet_size);
- free(tmp);
- free(eth);
- break;
- }
- }
- struct arp {
- uint16_t htype;
- uint16_t proto;
- uint8_t hlen;
- uint8_t plen;
- uint16_t oper;
- uint8_t sender_ha[6];
- uint32_t sender_ip;
- uint8_t target_ha[6];
- uint32_t target_ip;
- uint8_t padding[18];
- } __attribute__((packed));
- static size_t write_arp_response(uint8_t * buffer, struct arp * source) {
- size_t offset = 0;
- /* Then, let's write an ethernet frame */
- struct ethernet_packet eth_out = {
- .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .destination = BROADCAST_MAC,
- .type = htons(0x0806),
- };
- memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet));
- offset += sizeof(struct ethernet_packet);
- struct arp arp_out;
- arp_out.htype = source->htype;
- arp_out.proto = source->proto;
- arp_out.hlen = 6;
- arp_out.plen = 4;
- arp_out.oper = ntohs(2);
- arp_out.sender_ha[0] = _netif.hwaddr[0];
- arp_out.sender_ha[1] = _netif.hwaddr[1];
- arp_out.sender_ha[2] = _netif.hwaddr[2];
- arp_out.sender_ha[3] = _netif.hwaddr[3];
- arp_out.sender_ha[4] = _netif.hwaddr[4];
- arp_out.sender_ha[5] = _netif.hwaddr[5];
- arp_out.sender_ip = ntohl(_netif.source);
- arp_out.target_ha[0] = source->sender_ha[0];
- arp_out.target_ha[1] = source->sender_ha[1];
- arp_out.target_ha[2] = source->sender_ha[2];
- arp_out.target_ha[3] = source->sender_ha[3];
- arp_out.target_ha[4] = source->sender_ha[4];
- arp_out.target_ha[5] = source->sender_ha[5];
- arp_out.target_ip = source->sender_ip;
- memcpy(&buffer[offset], &arp_out, sizeof(struct arp));
- offset += sizeof(struct arp);
- return offset;
- }
- static size_t write_arp_request(uint8_t * buffer, uint32_t ip) {
- size_t offset = 0;
- debug_print(WARNING, "Request ARP from gateway address %x", ip);
- /* Then, let's write an ethernet frame */
- struct ethernet_packet eth_out = {
- .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .destination = BROADCAST_MAC,
- .type = htons(0x0806),
- };
- memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet));
- offset += sizeof(struct ethernet_packet);
- struct arp arp_out;
- arp_out.htype = ntohs(1);
- debug_print(WARNING, "Request ARP from gateway address %x", ip);
- arp_out.proto = ntohs(0x0800);
- arp_out.hlen = 6;
- arp_out.plen = 4;
- arp_out.oper = ntohs(1);
- arp_out.sender_ha[0] = _netif.hwaddr[0];
- arp_out.sender_ha[1] = _netif.hwaddr[1];
- arp_out.sender_ha[2] = _netif.hwaddr[2];
- arp_out.sender_ha[3] = _netif.hwaddr[3];
- arp_out.sender_ha[4] = _netif.hwaddr[4];
- arp_out.sender_ha[5] = _netif.hwaddr[5];
- arp_out.sender_ip = ntohl(_netif.source);
- arp_out.target_ha[0] = 0;
- arp_out.target_ha[1] = 0;
- arp_out.target_ha[2] = 0;
- arp_out.target_ha[3] = 0;
- arp_out.target_ha[4] = 0;
- arp_out.target_ha[5] = 0;
- arp_out.target_ip = ntohl(ip);
- memcpy(&buffer[offset], &arp_out, sizeof(struct arp));
- offset += sizeof(struct arp);
- return offset;
- }
- static void net_handle_arp(struct ethernet_packet * eth) {
- debug_print(WARNING, "ARP packet...");
- struct arp * arp = (struct arp *)ð->payload;
- char sender_ip[16];
- char target_ip[16];
- ip_ntoa(ntohl(arp->sender_ip), sender_ip);
- ip_ntoa(ntohl(arp->target_ip), target_ip);
- debug_print(WARNING, "%2x:%2x:%2x:%2x:%2x:%2x (%s) → %2x:%2x:%2x:%2x:%2x:%2x (%s) is",
- arp->sender_ha[0],
- arp->sender_ha[1],
- arp->sender_ha[2],
- arp->sender_ha[3],
- arp->sender_ha[4],
- arp->sender_ha[5],
- sender_ip,
- arp->target_ha[0],
- arp->target_ha[1],
- arp->target_ha[2],
- arp->target_ha[3],
- arp->target_ha[4],
- arp->target_ha[5],
- target_ip);
- if (ntohs(arp->oper) == 1) {
- if (ntohl(arp->target_ip) == _netif.source) {
- debug_print(WARNING, "That's us!");
- {
- void * tmp = malloc(1024);
- size_t packet_size = write_arp_response(tmp, arp);
- _netif.send_packet(tmp, packet_size);
- free(tmp);
- }
- }
- } else {
- if (ntohl(arp->target_ip) == _netif.source) {
- debug_print(WARNING, "It's a response to our query!");
- if (ntohl(arp->sender_ip) == _netif.gateway) {
- _gateway[0] = arp->sender_ha[0];
- _gateway[1] = arp->sender_ha[1];
- _gateway[2] = arp->sender_ha[2];
- _gateway[3] = arp->sender_ha[3];
- _gateway[4] = arp->sender_ha[4];
- _gateway[5] = arp->sender_ha[5];
- }
- } else {
- debug_print(WARNING, "Response to someone else...\n");
- }
- }
- }
- void net_handler(void * data, char * name) {
- /* Network Packet Handler*/
- _netif.extra = NULL;
- _dns_server = ip_aton("10.0.2.3");
- placeholder_dhcp();
- dns_waiters = list_create();
- _tcp_sockets = hashmap_create_int(0xFF);
- _udp_sockets = hashmap_create_int(0xFF);
- while (1) {
- struct ethernet_packet * eth = net_receive();
- if (!eth) continue;
- switch (ntohs(eth->type)) {
- case ETHERNET_TYPE_IPV4:
- net_handle_ipv4((struct ipv4_packet *)eth->payload);
- break;
- case ETHERNET_TYPE_ARP:
- net_handle_arp(eth);
- break;
- }
- free(eth);
- }
- }
- size_t write_dhcp_packet(uint8_t * buffer) {
- size_t offset = 0;
- size_t payload_size = sizeof(struct dhcp_packet);
- /* First, let's figure out how big this is supposed to be... */
- uint8_t dhcp_options[] = {
- 53, /* Message type */
- 1, /* Length: 1 */
- 1, /* Discover */
- 55,
- 2,
- 3,
- 6,
- 255, /* END */
- };
- payload_size += sizeof(dhcp_options);
- /* Then, let's write an ethernet frame */
- struct ethernet_packet eth_out = {
- .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .destination = BROADCAST_MAC,
- .type = htons(0x0800),
- };
- memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet));
- offset += sizeof(struct ethernet_packet);
- /* Prepare the IPv4 header */
- uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size);
- uint16_t _ident = htons(1);
- struct ipv4_packet ipv4_out = {
- .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */
- .dscp_ecn = 0, /* not setting either of those */
- .length = _length,
- .ident = _ident,
- .flags_fragment = 0,
- .ttl = 0x40,
- .protocol = IPV4_PROT_UDP,
- .checksum = 0, /* fill this in later */
- .source = htonl(ip_aton("0.0.0.0")),
- .destination = htonl(ip_aton("255.255.255.255")),
- };
- uint16_t checksum = calculate_ipv4_checksum(&ipv4_out);
- ipv4_out.checksum = htons(checksum);
- memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet));
- offset += sizeof(struct ipv4_packet);
- uint16_t _udp_source = htons(68);
- uint16_t _udp_destination = htons(67);
- uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size);
- /* Now let's build a UDP packet */
- struct udp_packet udp_out = {
- .source_port = _udp_source,
- .destination_port = _udp_destination,
- .length = _udp_length,
- .checksum = 0,
- };
- /* XXX calculate checksum here */
- memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet));
- offset += sizeof(struct udp_packet);
- /* BOOTP headers */
- struct dhcp_packet bootp_out = {
- .op = 1,
- .htype = 1,
- .hlen = 6, /* mac address... */
- .hops = 0,
- .xid = htonl(0x1337), /* transaction id */
- .secs = 0,
- .flags = 0,
- .ciaddr = 0x000000,
- .yiaddr = 0x000000,
- .siaddr = 0x000000,
- .giaddr = 0x000000,
- .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .sname = {0},
- .file = {0},
- .magic = htonl(DHCP_MAGIC),
- };
- memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet));
- offset += sizeof(struct dhcp_packet);
- memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options));
- offset += sizeof(dhcp_options);
- return offset;
- }
- size_t write_dhcp_request(uint8_t * buffer, uint8_t * ip) {
- size_t offset = 0;
- size_t payload_size = sizeof(struct dhcp_packet);
- /* First, let's figure out how big this is supposed to be... */
- uint8_t dhcp_options[] = {
- 53, /* Message type */
- 1, /* Length: 1 */
- 3, /* Request */
- 50,
- 4, /* requested ip */
- ip[0],ip[1],ip[2],ip[3],
- 55,
- 2,
- 3,
- 6,
- 255, /* END */
- };
- payload_size += sizeof(dhcp_options);
- /* Then, let's write an ethernet frame */
- struct ethernet_packet eth_out = {
- .source = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .destination = BROADCAST_MAC,
- .type = htons(0x0800),
- };
- memcpy(&buffer[offset], ð_out, sizeof(struct ethernet_packet));
- offset += sizeof(struct ethernet_packet);
- /* Prepare the IPv4 header */
- uint16_t _length = htons(sizeof(struct ipv4_packet) + sizeof(struct udp_packet) + payload_size);
- uint16_t _ident = htons(1);
- struct ipv4_packet ipv4_out = {
- .version_ihl = ((0x4 << 4) | (0x5 << 0)), /* 4 = ipv4, 5 = no options */
- .dscp_ecn = 0, /* not setting either of those */
- .length = _length,
- .ident = _ident,
- .flags_fragment = 0,
- .ttl = 0x40,
- .protocol = IPV4_PROT_UDP,
- .checksum = 0, /* fill this in later */
- .source = htonl(ip_aton("0.0.0.0")),
- .destination = htonl(ip_aton("255.255.255.255")),
- };
- uint16_t checksum = calculate_ipv4_checksum(&ipv4_out);
- ipv4_out.checksum = htons(checksum);
- memcpy(&buffer[offset], &ipv4_out, sizeof(struct ipv4_packet));
- offset += sizeof(struct ipv4_packet);
- uint16_t _udp_source = htons(68);
- uint16_t _udp_destination = htons(67);
- uint16_t _udp_length = htons(sizeof(struct udp_packet) + payload_size);
- /* Now let's build a UDP packet */
- struct udp_packet udp_out = {
- .source_port = _udp_source,
- .destination_port = _udp_destination,
- .length = _udp_length,
- .checksum = 0,
- };
- /* XXX calculate checksum here */
- memcpy(&buffer[offset], &udp_out, sizeof(struct udp_packet));
- offset += sizeof(struct udp_packet);
- /* BOOTP headers */
- struct dhcp_packet bootp_out = {
- .op = 1,
- .htype = 1,
- .hlen = 6, /* mac address... */
- .hops = 0,
- .xid = htonl(0x1337), /* transaction id */
- .secs = 0,
- .flags = 0,
- .ciaddr = 0x000000,
- .yiaddr = 0x000000,
- .siaddr = 0x000000,
- .giaddr = 0x000000,
- .chaddr = { _netif.hwaddr[0], _netif.hwaddr[1], _netif.hwaddr[2],
- _netif.hwaddr[3], _netif.hwaddr[4], _netif.hwaddr[5] },
- .sname = {0},
- .file = {0},
- .magic = htonl(DHCP_MAGIC),
- };
- memcpy(&buffer[offset], &bootp_out, sizeof(struct dhcp_packet));
- offset += sizeof(struct dhcp_packet);
- memcpy(&buffer[offset], &dhcp_options, sizeof(dhcp_options));
- offset += sizeof(dhcp_options);
- return offset;
- }
- static void parse_dns_response(fs_node_t * tty, void * last_packet) {
- struct udp_packet * udp = (struct udp_packet *)last_packet;
- uint16_t src_port = ntohs(udp->source_port);
- uint16_t dst_port = ntohs(udp->destination_port);
- uint16_t udp_len = ntohs(udp->length);
- fprintf(tty, "UDP [%d → %d] length=%d bytes\n",
- src_port, dst_port, udp_len);
- struct dns_packet * dns = (struct dns_packet *)udp->payload;
- uint16_t dns_questions = ntohs(dns->questions);
- uint16_t dns_answers = ntohs(dns->answers);
- fprintf(tty, "DNS - %d queries, %d answers\n",
- dns_questions, dns_answers);
- fprintf(tty, "Queries:\n");
- int offset = sizeof(struct dns_packet);
- int queries = 0;
- uint8_t * bytes = (uint8_t *)dns;
- while (queries < dns_questions) {
- offset = print_dns_name(tty, dns, offset);
- uint16_t * d = (uint16_t *)&bytes[offset];
- fprintf(tty, " - Type: %4x %4x\n", ntohs(d[0]), ntohs(d[1]));
- offset += 4;
- queries++;
- }
- fprintf(tty, "Answers:\n");
- int answers = 0;
- while (answers < dns_answers) {
- char buf[1024];
- size_t ret = dns_name_to_normal_name(dns, offset, buf);
- debug_print(WARNING, "%d - %s", ret, buf);
- offset = print_dns_name(tty, dns, offset);
- uint16_t * d = (uint16_t *)&bytes[offset];
- fprintf(tty, " - Type: %4x %4x; ", ntohs(d[0]), ntohs(d[1]));
- offset += 4;
- uint32_t * t = (uint32_t *)&bytes[offset];
- fprintf(tty, "TTL: %d; ", ntohl(t[0]));
- offset += 4;
- uint16_t * l = (uint16_t *)&bytes[offset];
- int _l = ntohs(l[0]);
- fprintf(tty, "len: %d; ", _l);
- offset += 2;
- if (_l == 4) {
- uint32_t * i = (uint32_t *)&bytes[offset];
- char ip[16];
- ip_ntoa(ntohl(i[0]), ip);
- fprintf(tty, " Address: %s\n", ip);
- debug_print(NOTICE, "Domain [%s] maps to [%s]", buf, ip);
- if (!hashmap_has(dns_cache, buf)) {
- hashmap_set(dns_cache, buf, strdup(ip));
- }
- } else {
- if (ntohs(d[0]) == 5) {
- fprintf(tty, "CNAME: ");
- char buffer[256];
- get_dns_name(buffer, dns, offset);
- fprintf(tty, "%s\n", buffer);
- if (strlen(buffer)) {
- buffer[strlen(buffer)-1] = '\0';
- }
- uint32_t addr;
- if (gethost(buffer,&addr) == 2) {
- debug_print(WARNING,"Can't provide a response yet, but going to query again in a moment.");
- } else {
- if (!hashmap_has(dns_cache, buf)) {
- char ip[16];
- ip_ntoa(addr, ip);
- hashmap_set(dns_cache, buf, strdup(ip));
- fprintf(tty, "resolves to %s\n", ip);
- }
- }
- } else {
- fprintf(tty, "dunno\n");
- }
- }
- offset += _l;
- answers++;
- }
- wakeup_queue(dns_waiters);
- }
- static fs_node_t * netfs_create(void) {
- fs_node_t * fnode = malloc(sizeof(fs_node_t));
- memset(fnode, 0x00, sizeof(fs_node_t));
- fnode->inode = 0;
- strcpy(fnode->name, "net");
- fnode->mask = 0555;
- fnode->flags = FS_DIRECTORY;
- fnode->readdir = readdir_netfs;
- fnode->finddir = finddir_netfs;
- fnode->ioctl = ioctl_netfs;
- fnode->nlink = 1;
- return fnode;
- }
- static int init(void) {
- dns_cache = hashmap_create(10);
- hashmap_set(dns_cache, "dakko.us", strdup("104.131.140.26"));
- hashmap_set(dns_cache, "toaruos.org", strdup("104.131.140.26"));
- hashmap_set(dns_cache, "www.toaruos.org", strdup("104.131.140.26"));
- hashmap_set(dns_cache, "www.yelp.com", strdup("104.16.57.23"));
- hashmap_set(dns_cache, "s3-media2.fl.yelpcdn.com", strdup("199.27.79.175"));
- hashmap_set(dns_cache, "forum.osdev.org", strdup("173.255.206.39"));
- hashmap_set(dns_cache, "wolfgun.puckipedia.com", strdup("104.47.147.203"));
- hashmap_set(dns_cache, "irc.freenode.net", strdup("91.217.189.42"));
- hashmap_set(dns_cache, "i.imgur.com", strdup("23.235.47.193"));
- /* /dev/net/{domain|ip}/{protocol}/{port} */
- vfs_mount("/dev/net", netfs_create());
- return 0;
- }
- static int fini(void) {
- return 0;
- }
- MODULE_DEF(net, init, fini);
|