├── .gitignore ├── Docs ├── ARP.md ├── Ethernet.md ├── ICMP.md ├── IP.md ├── IPv6.md ├── TCP.md └── UDP.md ├── LICENSE ├── Makefile ├── README.md ├── app.ld ├── build.sh └── minIP.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Libraries 2 | libBareMetal.c 3 | libBareMetal.h 4 | 5 | # macOS 6 | .DS_Store 7 | 8 | # Object files 9 | *.o 10 | *.ko 11 | *.obj 12 | *.elf 13 | 14 | # Precompiled Headers 15 | *.gch 16 | *.pch 17 | 18 | # Libraries 19 | *.lib 20 | *.a 21 | *.la 22 | *.lo 23 | 24 | # Shared objects (inc. Windows DLLs) 25 | *.dll 26 | *.so 27 | *.so.* 28 | *.dylib 29 | 30 | # Executables 31 | *.exe 32 | *.out 33 | *.app 34 | *.i*86 35 | *.x86_64 36 | *.hex 37 | -------------------------------------------------------------------------------- /Docs/ARP.md: -------------------------------------------------------------------------------- 1 | 2 | ARP 3 | ======== 4 | 5 | ARP (Address Resolution Protocol) is used to find out what hardware addresses resolves to a specific IP address. 6 | 7 | Let's say you have two computers: 8 | 9 | Computer A 10 | IP: 10.0.0.10 11 | HW: 0B4D23C20341 12 | 13 | Computer B 14 | IP: 10.0.0.20 15 | HW: 0C34A3B98012 16 | 17 | Computer A wants to connect to computer B via its IP address but in order to send an Ethernet packet it needs to know what the hardware address of computer B is. 18 | 19 | ARP to the rescue! 20 | 21 | Computer A first has to send a broadcast asking the network for the hardware address. 22 | 23 | Anatomy of an ARP request/reply 24 | -------- 25 | 26 | ARP request packet layout: 27 | 28 | Ethernet header: 29 | 0-5, Broadcast MAC (0xFFFFFFFFFFFF) 30 | 6-11, Source MAC (The requestor) 31 | 12-13, Type ARP (0x0806) 32 | ARP header: 33 | 14-15, Hardware type (0x0001 Ethernet) 34 | 16-17, Protocol type (0x0800 IP) 35 | 18, Hardware size (0x06) 36 | 19, Protocol size (0x04) 37 | 20-21, Opcode (0x0001 Request) 38 | 22-27, Sender MAC (The requestor) 39 | 28-31, Sender IP (The requestor) 40 | 32-37, Target MAC (0x000000000000) 41 | 38-41, Target IP (The query) 42 | 43 | ARP reply packet layout: 44 | 45 | Ethernet header: 46 | 0-5, Destination MAC (The requestor) 47 | 6-11, Source MAC (The replier) 48 | 12-13, Type ARP (0x0806) 49 | ARP header: 50 | 14-15, Hardware type (0x0001 Ethernet) 51 | 16-17, Protocol type (0x0800 IP) 52 | 18, Hardware size (0x06) 53 | 19, Protocol size (0x04) 54 | 20-21, Opcode (0x0002 Reply) 55 | 22-27, Sender MAC (The replier) 56 | 28-31, Sender IP (The replier) 57 | 32-37, Target MAC (The requestor) 58 | 38-41, Target IP (The requestor) 59 | 60 | ARP Caching 61 | -------- 62 | 63 | The operating system maintains a cache of ARP responses so it will not need to send out a request for the MAC of a device it has already been in contact with. On Windows and Linux you can see this cache by executing the following command: 64 | 65 | arp -a 66 | 67 | ARP Spoofing 68 | -------- 69 | 70 | Yes, it is also possible to cause network issues by sending bogus ARP replies. This is generally frowned upon by network admins. 71 | -------------------------------------------------------------------------------- /Docs/Ethernet.md: -------------------------------------------------------------------------------- 1 | 2 | Ethernet 3 | ======== 4 | 5 | Ethernet (refered to those in the industry as "IEEE 802.3") is the physical connection to your local network. 6 | 7 | Ethernet header layout: 8 | 9 | Ethernet header: 10 | 0-5, Destination MAC 11 | 6-11, Source MAC 12 | 12-13, EtherType/Length 13 | Ethernet data: 14 | 14-1500 15 | 16 | Ethernet header diagram: 17 | 18 | ┌───────────────────────────────────────────────────────────────┐ 19 | │0 1 2 3 │ 20 | │0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1│ 21 | ├───────────────────────────────────────────────────────────────┤ 22 | │ Destination MAC Address │ 23 | ├───────────────────────────────┬───────────────────────────────┤ 24 | │ Destination MAC Continued │ Source MAC Address │ 25 | ├───────────────────────────────┴───────────────────────────────┤ 26 | │ Source MAC Continued │ 27 | ├───────────────────────────────┬───────────────────────────────┘ 28 | │ EtherType │ 29 | └───────────────────────────────┘ -------------------------------------------------------------------------------- /Docs/ICMP.md: -------------------------------------------------------------------------------- 1 | 2 | ICMP 3 | ======== 4 | 5 | ICMP (Internet Control Message Protocol) 6 | 7 | 8 | Anatomy of an ICMP request/reply 9 | -------- 10 | 11 | ICMP builds upon IP so you'll see familiar IP headers here. 12 | 13 | ICMP ping request packet layout: 14 | 15 | Ethernet header: 16 | 0-5, Destination MAC 17 | 6-11, Source MAC 18 | 12-13, Type IP (0x0800) 19 | IP header: 20 | 14, Version/Header Length (Usually 0x45) 21 | 15, Differentiated Services Field (0x00) 22 | 16-17, Total Length 23 | 18-19, Identification 24 | 20-21, Flags/Fragment Offset 25 | 22, Time To Live (Usually 0x40) 26 | 23, Protocol (0x01 for ICMP) 27 | 24-25, Header Checksum 28 | 26-29, Source IP 29 | 30-33, Destination IP 30 | ICMP header: 31 | 34, Type (0x08, Ping request) 32 | 35, Code 33 | 36-37, Checksum 34 | 38-39, Identifier 35 | 40-41, Sequence number 36 | 42-49, Timestamp 37 | 50-??, Data 38 | 39 | ICMP ping reply packet layout: 40 | 41 | Ethernet header: 42 | 0-5, Destination MAC 43 | 6-11, Source MAC 44 | 12-13, Type IP (0x0800) 45 | IP header: 46 | 14, Version/Header Length 47 | 15, Differentiated Services Field 48 | 16-17, Total Length 49 | 18-19, Identification 50 | 20-21, Flags/Fragment Offset 51 | 22, Time To Live 52 | 23, Protocol (0x01 for ICMP) 53 | 24-25, Header Checksum 54 | 26-29, Source IP 55 | 30-33, Destination IP 56 | ICMP header: 57 | 34, Type (0x00, Ping reply) 58 | 35, Code 59 | 36-37, Checksum 60 | 38-39, Identifier 61 | 40-41, Sequence number 62 | 42-49, Timestamp 63 | 50-??, Data 64 | -------------------------------------------------------------------------------- /Docs/IP.md: -------------------------------------------------------------------------------- 1 | 2 | IP 3 | ======== 4 | 5 | IP (Internet Protocol) is, well, how the internet communicates. This is also known as IPv4 or "Internet Classic". 6 | 7 | Anatomy of an IP packet 8 | -------- 9 | 10 | IP acts as a building block for more complex protocols. 11 | 12 | IP packet layout: 13 | 14 | Ethernet header: 15 | 0-5, Destination MAC 16 | 6-11, Source MAC 17 | 12-13, Type IP (0x0800) 18 | IP header: 19 | 14, Version/Header Length 20 | Bits 0-3 Version (Set to 0x4) 21 | Bits 4-7 Header length in 32-bit words (Minimum 5 aka 20 bytes) 22 | 15, Differentiated Services Field (0x00) 23 | 16-17, Total Length 24 | 18-19, Identification 25 | 20-21, Flags/Fragment Offset 26 | Bits 0-2 Flags 27 | Bits 3-15 Fragment Offset 28 | 22, Time To Live (Usually 0x40) 29 | 23, Protocol 30 | 24-25, Header Checksum 31 | 26-29, Source IP 32 | 30-33, Destination IP 33 | 34 | IP packet diagram: 35 | 36 | ┌───────────────────────────────────────────────────────────────┐ 37 | │0 1 2 3 │ 38 | │0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1│ 39 | ├───────┬───────┬───────────────┬───────────────────────────────┤ 40 | │Version│ IHL │ DSF │ Total Length │ 41 | ├───────┴───────┴───────────────┼─────┬─────────────────────────┤ 42 | │ Identification │Flags│ Fragment Offset │ 43 | ├───────────────┬───────────────┼─────┴─────────────────────────┤ 44 | │ Time To Live │ Protocol │ Header Checksum │ 45 | ├───────────────┴───────────────┴───────────────────────────────┤ 46 | │ Source IP │ 47 | ├───────────────────────────────────────────────────────────────┤ 48 | │ Destination IP │ 49 | └───────────────────────────────────────────────────────────────┘ -------------------------------------------------------------------------------- /Docs/IPv6.md: -------------------------------------------------------------------------------- 1 | 2 | IPv6 3 | ==== 4 | 5 | IPv6 (Internet Protocol version 6) is the successor of IPv4. Yep, the IETF (Internet Engineering Task Force) has been skipping version numbers since before Microsoft thought it was cool. 6 | 7 | Anatomy of an IPv6 packet 8 | -------- 9 | 10 | IPv6 acts as a building block for more complex protocols. 11 | 12 | IPv6 packet layout: 13 | 14 | Ethernet header: 15 | 0-5, Destination MAC 16 | 6-11, Source MAC 17 | 12-13, Type IPv6 (0x86DD) 18 | IPv6 header: 19 | 14-17, Version/Class/Flow Label 20 | Bits 0-3 Version, set to 6 (0110) 21 | Bits 4-11 Traffic Class 22 | Bits 12-31 Flow Label 23 | 18-19, Payload Length 24 | 20, Next Header 25 | 21, Hop Limit 26 | 22-37, Source Address 27 | 38-53, Destination Address 28 | 29 | IP packet diagram: 30 | 31 | ┌───────────────────────────────────────────────────────────────┐ 32 | │0 1 2 3 │ 33 | │0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1│ 34 | ├───────┬───────────────┬───────────────────────────────────────┤ 35 | │Version│ Traffic Class │ Flow Label │ 36 | ├───────┴───────────────┴───────┬───────────────┬───────────────┤ 37 | │ Payload Length │ Next Header │ Hop Limit │ 38 | ├───────────────────────────────┴───────────────┴───────────────┤ 39 | │ Source IP │ 40 | ├───────────────────────────────────────────────────────────────┤ 41 | │ │ 42 | ├───────────────────────────────────────────────────────────────┤ 43 | │ │ 44 | ├───────────────────────────────────────────────────────────────┤ 45 | │ │ 46 | ├───────────────────────────────────────────────────────────────┤ 47 | │ Destination IP │ 48 | ├───────────────────────────────────────────────────────────────┤ 49 | │ │ 50 | ├───────────────────────────────────────────────────────────────┤ 51 | │ │ 52 | ├───────────────────────────────────────────────────────────────┤ 53 | │ │ 54 | └───────────────────────────────────────────────────────────────┘ 55 | -------------------------------------------------------------------------------- /Docs/TCP.md: -------------------------------------------------------------------------------- 1 | 2 | TCP 3 | ======== 4 | 5 | TCP (Transmission Control Protocol) also known as [RFC 793](http://tools.ietf.org/html/rfc793). 6 | 7 | 8 | Anatomy of an TCP packet 9 | -------- 10 | 11 | TCP builds upon IP so you'll see familiar IP headers here. 12 | 13 | TCP packet layout: 14 | 15 | Ethernet header: 16 | 0-5, Destination MAC 17 | 6-11, Source MAC 18 | 12-13, Type IP (0x0800) 19 | IP header: 20 | 14, Version/Header Length (Usually 0x45) 21 | 15, Differentiated Services Field (0x00) 22 | 16-17, Total Length 23 | 18-19, Identification 24 | 20-21, Flags/Fragment Offset 25 | 22, Time To Live (Usually 0x40) 26 | 23, Protocol (0x06 for TCP) 27 | 24-25, Header Checksum 28 | 26-29, Source IP 29 | 30-33, Destination IP 30 | TCP header: 31 | 34-35, Source Port 32 | 36-37, Destination Port 33 | 38-41, Sequence Number 34 | 42-45, Acknowledgement Number 35 | 46-47, Data Offset/Flags 36 | 48-49, Window Size 37 | 50-51, Checksum 38 | 52-53, Urgent Pointer 39 | 40 | TCP Packet diagram: 41 | 42 | 43 | ┌───────────────────────────────────────────────────────────────┐ 44 | │0 1 2 3 │ 45 | │0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1│ 46 | ├───────────────────────────────┬───────────────────────────────┤ 47 | │ Source Port │ Destination Port │ 48 | ├───────────────────────────────┴───────────────────────────────┤ 49 | │ Sequence Number │ 50 | ├───────────────────────────────────────────────────────────────┤ 51 | │ Acknowledgement Number │ 52 | ├───────┬───────────┬─┬─┬─┬─┬─┬─┬───────────────────────────────┤ 53 | │ Data │ │U│A│P│R│S│F│ │ 54 | │Offset │ Reserved │R│C│S│S│Y│I│ Window Size │ 55 | │ │ │G│K│H│T│N│N│ │ 56 | ├───────┴───────────┴─┴─┴─┴─┴─┴─┼───────────────────────────────┤ 57 | │ Checksum │ Urgent Pointer │ 58 | └───────────────────────────────┴───────────────────────────────┘ 59 | 60 | The TCP Handshake 61 | ------ 62 | 63 | It's as easy as 1-2-3! Really! 64 | 65 | Client: "Hi! I'd like to connect to you. Is that ok?" 66 | 67 | Server: "Sure, I'll allow that." 68 | 69 | Client: "Thanks!" 70 | 71 | 72 | ╔═══════════════════╗ 73 | ║TCP 3-way handshake║ 74 | ╚═══════════════════╝ 75 | 76 | ┌────────┐ ┌────────┐ 77 | │ Client │ ──────┬───┬─────▶ │ Server │ 78 | └────────┘ │SYN│ └────────┘ 79 | └───┘ 80 | ┌────────┐ ┌────────┐ 81 | │ Client │ ◀───┬───────┬──── │ Server │ 82 | └────────┘ │SYN/ACK│ └────────┘ 83 | └───────┘ 84 | ┌────────┐ ┌────────┐ 85 | │ Client │ ──────┬───┬─────▶ │ Server │ 86 | └────────┘ │ACK│ └────────┘ 87 | └───┘ 88 | 89 | The client wants to connect to a server and sends a SYN (SYNchronize) packet. The server then responds with a SYN-ACK (SYNchronize-ACKnowledge) packet. The client sends the server a ACK (ACKnowledge) packet. 90 | -------------------------------------------------------------------------------- /Docs/UDP.md: -------------------------------------------------------------------------------- 1 | 2 | UDP 3 | ======== 4 | 5 | UDP (User Datagram Protocol) also known as [RFC 768](http://tools.ietf.org/html/rfc768). 6 | 7 | 8 | Anatomy of an UDP packet 9 | -------- 10 | 11 | UDP builds upon IP so you'll see familiar IP headers here. 12 | 13 | UDP packet layout: 14 | 15 | Ethernet header: 16 | 0-5, Destination MAC 17 | 6-11, Source MAC 18 | 12-13, Type IP (0x0800) 19 | IP header: 20 | 14, Version/Header Length (Usually 0x45) 21 | 15, Differentiated Services Field (0x00) 22 | 16-17, Total Length 23 | 18-19, Identification 24 | 20-21, Flags/Fragment Offset 25 | 22, Time To Live (Usually 0x40) 26 | 23, Protocol (0x11 for UDP) 27 | 24-25, Header Checksum 28 | 26-29, Source IP 29 | 30-33, Destination IP 30 | UDP header: 31 | 34-35, Source Port 32 | 36-37, Destination Port 33 | 38-39, Length 34 | 40-41, Checksum (Can be set to 0x0000) 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Ian Seyler 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: 2 | gcc -Wall -o minIP minIP.c -DLINUX 3 | clean: 4 | rm -f minIP 5 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | minIP 2 | ======== 3 | 4 | A minimalist IP stack written in ANSI C. 5 | 6 | This needs to be run on a Linux machine with root access - ideally on a network interface that does not have an IP address already associated with it. 7 | 8 | This also runs on top of the BareMetal exokernel. 9 | 10 | 11 | Goals 12 | -------- 13 | 14 | Provide enough of a stack to serve a simple static webpage. 15 | 16 | 17 | Building 18 | -------- 19 | 20 | Linux: 21 | 22 | make 23 | 24 | BareMetal: 25 | 26 | This version uses hardcoded IP addresses. Make sure to update them if needed in main(). 27 | 28 | ./build.sh 29 | 30 | 31 | Usage 32 | -------- 33 | 34 | Linux: 35 | 36 | ./minIP eth1 192.168.0.99 255.255.255.0 192.168.0.1 37 | 38 | BareMetal: 39 | 40 | minIP.app 41 | 42 | 43 | Why 44 | -------- 45 | 46 | If this can be done in Python (see [teeceepee](https://github.com/jvns/teeceepee) and its [blog post](http://jvns.ca/blog/2014/08/12/what-happens-if-you-write-a-tcp-stack-in-python/)), then it can be done in C! 47 | 48 | Also, its a great proof of concept to learn the fundamentals in preparation for an x86-64 assembly re-write I plan on doing in the future. 49 | 50 | 51 | What works 52 | -------- 53 | 54 | Protocol | Functional 55 | -----|----- 56 | ARP | yes 57 | IP | partially 58 | ICMP | yes 59 | TCP | partially 60 | UDP | no 61 | TCPv6 | no 62 | UDPv6 | no 63 | 64 | 65 | Todo 66 | -------- 67 | - Resending dropped packets 68 | - Large packet support 69 | - Handling more than one incoming connection at once 70 | -------------------------------------------------------------------------------- /app.ld: -------------------------------------------------------------------------------- 1 | OUTPUT_FORMAT("binary") 2 | OUTPUT_ARCH("i386:x86-64") 3 | ENTRY(main) 4 | SECTIONS 5 | { 6 | . = 0xFFFF800000000000; 7 | .text : { 8 | *(.text) 9 | . = ALIGN(16); 10 | } 11 | .data : { 12 | *(.data) 13 | *(.rodata) 14 | . = ALIGN(16); 15 | } 16 | __bss_start = .; 17 | .bss : { 18 | bss = .; _bss = .; __bss = .; 19 | *(.bss); 20 | } 21 | end = .; _end = .; __end = .; 22 | } -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | rm libBareMetal.c 3 | rm libBareMetal.h 4 | if [ -x "$(command -v curl)" ]; then 5 | curl -s -o libBareMetal.c https://raw.githubusercontent.com/ReturnInfinity/BareMetal/master/api/libBareMetal.c 6 | curl -s -o libBareMetal.h https://raw.githubusercontent.com/ReturnInfinity/BareMetal/master/api/libBareMetal.h 7 | else 8 | wget -q https://raw.githubusercontent.com/ReturnInfinity/BareMetal/master/api/libBareMetal.c 9 | wget -q https://raw.githubusercontent.com/ReturnInfinity/BareMetal/master/api/libBareMetal.h 10 | fi 11 | gcc -c -m64 -Wall -W -pedantic -std=c99 -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -fomit-frame-pointer -mno-red-zone -o minIP.o minIP.c -DBAREMETAL 12 | gcc -c -m64 -Wall -W -pedantic -fno-builtin -nostdlib -nostartfiles -nodefaultlibs -fomit-frame-pointer -mno-red-zone -o libBareMetal.o libBareMetal.c 13 | objcopy --remove-section .comment minIP.o 14 | objcopy --remove-section .eh_frame minIP.o 15 | objcopy --remove-section .comment libBareMetal.o 16 | objcopy --remove-section .eh_frame libBareMetal.o 17 | ld -T app.ld -o minIP.app minIP.o libBareMetal.o 18 | -------------------------------------------------------------------------------- /minIP.c: -------------------------------------------------------------------------------- 1 | /* minIP */ 2 | /* Written by Ian Seyler */ 3 | 4 | // Linux compile: gcc minIP.c -o minIP 5 | // Linux usage: ./minIP eth1 192.168.0.99 255.255.255.0 192.168.0.1 6 | 7 | // BareMetal compile: ./build.sh 8 | // BareMetal usage: minIP.app 9 | 10 | #define __USE_MISC 11 | 12 | /* Global Includes */ 13 | #if defined(BAREMETAL) 14 | #include "libBareMetal.h" 15 | #endif 16 | #if defined(LINUX) 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #endif 28 | 29 | /* Typedefs */ 30 | #if defined(BAREMETAL) 31 | typedef unsigned char u8; 32 | typedef unsigned short u16; 33 | typedef unsigned int u32; 34 | typedef unsigned long long u64; 35 | #else 36 | typedef uint8_t u8; 37 | typedef uint16_t u16; 38 | typedef uint32_t u32; 39 | typedef uint64_t u64; 40 | #endif 41 | 42 | /* Global functions */ 43 | u16 checksum(u8* data, u16 bytes); 44 | u16 checksum_tcp(u8* data, u16 bytes, u16 protocol, u16 length); 45 | #if defined(BAREMETAL) 46 | int net_init(); 47 | #else 48 | int net_init(char *interface); 49 | #endif 50 | int net_exit(); 51 | int net_send(unsigned char* data, unsigned int bytes); 52 | int net_recv(unsigned char* data); 53 | u16 swap16(u16 in); 54 | u32 swap32(u32 in); 55 | #if defined(BAREMETAL) 56 | void* memset(void* s, int c, int n); 57 | void* memcpy(void* d, const void* s, int n); 58 | int strlen(const char* s); 59 | #endif 60 | 61 | /* Global defines */ 62 | #undef ETH_FRAME_LEN 63 | #define ETH_FRAME_LEN 1518 64 | #define ETHERTYPE_ARP 0x0806 65 | #define ETHERTYPE_IPv4 0x0800 66 | #define ETHERTYPE_IPv6 0x86DD 67 | #define ARP_REQUEST 1 68 | #define ARP_REPLY 2 69 | #define PROTOCOL_IP_ICMP 1 70 | #define PROTOCOL_IP_TCP 6 71 | #define PROTOCOL_IP_UDP 11 72 | #define ICMP_ECHO_REPLY 0 73 | #define ICMP_ECHO_REQUEST 8 74 | #define TCP_ACK 16 75 | #define TCP_PSH 8 76 | #define TCP_RST 4 77 | #define TCP_SYN 2 78 | #define TCP_FIN 1 79 | 80 | /* Global variables */ 81 | u8 src_MAC[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 82 | u8 dst_MAC[6] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; 83 | u8 dst_broadcast[6] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff}; 84 | u8 src_IP[4] = {0, 0, 0, 0}; 85 | u8 src_SN[4] = {0, 0, 0, 0}; 86 | u8 src_GW[4] = {0, 0, 0, 0}; 87 | u8 dst_IP[4] = {0, 0, 0, 0}; 88 | unsigned char buffer[ETH_FRAME_LEN]; 89 | unsigned char tosend[ETH_FRAME_LEN]; 90 | int s; // Socket variable 91 | int running = 1, c, recv_packet_len; 92 | unsigned int tint, tint0, tint1, tint2, tint3; 93 | #if !defined(BAREMETAL) 94 | struct sockaddr_ll sa; 95 | struct ifreq ifr; 96 | #endif 97 | 98 | /* Global structs */ 99 | #pragma pack(1) 100 | typedef struct eth_header { 101 | u8 dest_mac[6]; 102 | u8 src_mac[6]; 103 | u16 type; 104 | } eth_header; // 14 bytes 105 | typedef struct arp_packet { 106 | eth_header ethernet; 107 | u16 hardware_type; 108 | u16 protocol; 109 | u8 hardware_size; 110 | u8 protocol_size; 111 | u16 opcode; 112 | u8 sender_mac[6]; 113 | u8 sender_ip[4]; 114 | u8 target_mac[6]; 115 | u8 target_ip[4]; 116 | } arp_packet; // 28 bytes 117 | typedef struct ipv4_packet { 118 | eth_header ethernet; 119 | u8 version; 120 | u8 dsf; 121 | u16 total_length; 122 | u16 id; 123 | u16 flags; 124 | u8 ttl; 125 | u8 protocol; 126 | u16 checksum; 127 | u8 src_ip[4]; 128 | u8 dest_ip[4]; 129 | } ipv4_packet; // 20 bytes since we don't support options 130 | typedef struct icmp_packet { 131 | ipv4_packet ipv4; 132 | u8 type; 133 | u8 code; 134 | u16 checksum; 135 | u16 id; 136 | u16 sequence; 137 | u64 timestamp; 138 | u8 data[2]; // Set to 2 so can be used as pointer 139 | } icmp_packet; 140 | typedef struct udp_packet { 141 | ipv4_packet ipv4; 142 | u16 src_port; 143 | u16 dest_port; 144 | u16 length; 145 | u16 checksum; 146 | u8 data[2]; // Set to 2 so can be used as pointer 147 | } udp_packet; 148 | typedef struct tcp_packet { 149 | ipv4_packet ipv4; 150 | u16 src_port; 151 | u16 dest_port; 152 | u32 seqnum; 153 | u32 acknum; 154 | u8 data_offset; 155 | u8 flags; 156 | u16 window; 157 | u16 checksum; 158 | u16 urg_pointer; 159 | // Options and data 160 | // u8 data[2]; // Set to 2 so can be used as pointer 161 | } tcp_packet; 162 | 163 | /* Default HTTP page with HTTP headers */ 164 | const char webpage[] = 165 | "HTTP/1.0 200 OK\n" 166 | "Server: BareMetal (http://www.returninfinity.com)\n" 167 | "Content-type: text/html\n" 168 | "\n" 169 | "\n" 170 | "\n" 171 | "\t\n" 172 | "\t\tminIP\n" 173 | "\t\t\n" 174 | "\t\t\n" 175 | "\t\t\n" 181 | "\t\n" 182 | "\t\n" 183 | "\t\t
\n" 184 | "\t\t\t

\n" 185 | "\t\t\t

Hello, from minIP!

\n" 186 | "\t\t\t

minIP on GitHub

\n" 187 | "\t\t\t

minIP is a very tiny TCP/IP stack implementation in C.

\n" 188 | "\t\t\t

It cointains just enough code to serve this webpage.

\n" 189 | "\t\t
\n" 190 | "\t\n" 191 | "\n"; 192 | const char version_string[] = "minIP v0.7.0 (2023 11 11)\n"; 193 | #if defined(BAREMETAL) 194 | const char arp[] = "arp\n"; 195 | const char ipv4[] = "ipv4\n"; 196 | const char ping[] = "ping\n"; 197 | 198 | #endif 199 | 200 | /* Main code */ 201 | #if defined(BAREMETAL) 202 | int main() 203 | #else 204 | int main(int argc, char *argv[]) 205 | #endif 206 | { 207 | #if defined(BAREMETAL) 208 | b_output(version_string, (unsigned long)strlen(version_string)); 209 | src_IP[0] = 192; 210 | src_IP[1] = 168; 211 | src_IP[2] = 4; 212 | src_IP[3] = 250; 213 | src_SN[0] = 255; 214 | src_SN[1] = 255; 215 | src_SN[2] = 255; 216 | src_SN[3] = 0; 217 | src_GW[0] = 192; 218 | src_GW[1] = 168; 219 | src_GW[2] = 4; 220 | src_GW[3] = 1; 221 | net_init(); 222 | #else 223 | printf(version_string); 224 | 225 | /* first argument needs to be a NIC */ 226 | if (argc < 5) 227 | { 228 | printf("Insufficient arguments!\n"); 229 | printf("%s interface ip subnet gw\n", argv[0]); 230 | exit(0); 231 | } 232 | 233 | /* Parse the IP and Subnet */ 234 | sscanf(argv[2], "%u.%u.%u.%u", &tint0, &tint1, &tint2, &tint3); 235 | src_IP[0] = tint0; 236 | src_IP[1] = tint1; 237 | src_IP[2] = tint2; 238 | src_IP[3] = tint3; 239 | sscanf(argv[3], "%u.%u.%u.%u", &tint0, &tint1, &tint2, &tint3); 240 | src_SN[0] = tint0; 241 | src_SN[1] = tint1; 242 | src_SN[2] = tint2; 243 | src_SN[3] = tint3; 244 | sscanf(argv[4], "%u.%u.%u.%u", &tint0, &tint1, &tint2, &tint3); 245 | src_GW[0] = tint0; 246 | src_GW[1] = tint1; 247 | src_GW[2] = tint2; 248 | src_GW[3] = tint3; 249 | 250 | net_init(argv[1]); // Get us a socket that can handle raw Ethernet frames 251 | 252 | printf("\n"); 253 | printf("This host:\n"); 254 | printf("HW: %02X:%02X:%02X:%02X:%02X:%02X\n", src_MAC[0], src_MAC[1], src_MAC[2], src_MAC[3], src_MAC[4], src_MAC[5]); 255 | printf("IP: %u.%u.%u.%u\n", src_IP[0], src_IP[1], src_IP[2], src_IP[3]); 256 | printf("SN: %u.%u.%u.%u\n", src_SN[0], src_SN[1], src_SN[2], src_SN[3]); 257 | printf("GW: %u.%u.%u.%u\n", src_GW[0], src_GW[1], src_GW[2], src_GW[3]); 258 | printf("\n"); 259 | #endif 260 | 261 | while(running == 1) 262 | { 263 | recv_packet_len = net_recv(buffer); 264 | eth_header* rx = (eth_header*)buffer; 265 | 266 | if (recv_packet_len > 0) // Make sure we received a packet 267 | { 268 | memset(tosend, 0, ETH_FRAME_LEN); // clear the send buffer 269 | if (swap16(rx->type) == ETHERTYPE_ARP) 270 | { 271 | arp_packet* rx_arp = (arp_packet*)buffer; 272 | if (swap16(rx_arp->opcode) == ARP_REQUEST) 273 | { 274 | #if defined(BAREMETAL) 275 | b_output(arp, (unsigned long)strlen(arp)); 276 | #endif 277 | #if defined(LINUX) 278 | printf("ARP Request - Who is %d.%d.%d.%d? Tell %d.%d.%d.%d\n", buffer[38], buffer[39], buffer[40], buffer[41], buffer[28], buffer[29], buffer[30], buffer[31]); 279 | #endif 280 | if (*(u32*)rx_arp->target_ip == *(u32*)src_IP) 281 | { 282 | #if defined(LINUX) 283 | printf("ARP Response - Sent\n"); 284 | #endif 285 | arp_packet* tx_arp = (arp_packet*)tosend; 286 | // Ethernet 287 | memcpy(tx_arp->ethernet.dest_mac, rx_arp->sender_mac, 6); 288 | memcpy(tx_arp->ethernet.src_mac, src_MAC, 6); 289 | tx_arp->ethernet.type = swap16(ETHERTYPE_ARP); 290 | // ARP 291 | tx_arp->hardware_type = swap16(1); // Ethernet 292 | tx_arp->protocol = swap16(ETHERTYPE_IPv4); 293 | tx_arp->hardware_size = 6; 294 | tx_arp->protocol_size = 4; 295 | tx_arp->opcode = swap16(ARP_REPLY); 296 | memcpy(tx_arp->sender_mac, src_MAC, 6); 297 | memcpy(tx_arp->sender_ip, rx_arp->target_ip, 4); 298 | memcpy(tx_arp->target_mac, rx_arp->sender_mac, 6); 299 | memcpy(tx_arp->target_ip, rx_arp->sender_ip, 4); 300 | // Send the reply 301 | net_send(tosend, 42); 302 | } 303 | } 304 | else if (buffer[21] == ARP_REPLY) 305 | { 306 | // TODO - Responses to our requests 307 | } 308 | } 309 | else if (swap16(rx->type) == ETHERTYPE_IPv4) 310 | { 311 | ipv4_packet* rx_ipv4 = (ipv4_packet*)buffer; 312 | if(rx_ipv4->protocol == PROTOCOL_IP_ICMP) 313 | { 314 | icmp_packet* rx_icmp = (icmp_packet*)buffer; 315 | if(rx_icmp->type == ICMP_ECHO_REQUEST) 316 | { 317 | if (*(u32*)rx_icmp->ipv4.dest_ip == *(u32*)src_IP) 318 | { 319 | #if defined(BAREMETAL) 320 | b_output(ping, (unsigned long)strlen(ping)); 321 | #endif 322 | #if defined(LINUX) 323 | printf("Ping Request from %d.%d.%d.%d. Sending response.\n", buffer[30], buffer[31], buffer[32], buffer[33]); 324 | #endif 325 | // Reply to the ping request 326 | icmp_packet* tx_icmp = (icmp_packet*)tosend; 327 | // Ethernet 328 | memcpy(tx_icmp->ipv4.ethernet.dest_mac, rx_icmp->ipv4.ethernet.src_mac, 6); 329 | memcpy(tx_icmp->ipv4.ethernet.src_mac, src_MAC, 6); 330 | tx_icmp->ipv4.ethernet.type = swap16(ETHERTYPE_IPv4); 331 | // IPv4 332 | tx_icmp->ipv4.version = rx_icmp->ipv4.version; 333 | tx_icmp->ipv4.dsf = rx_icmp->ipv4.dsf; 334 | tx_icmp->ipv4.total_length = rx_icmp->ipv4.total_length; 335 | tx_icmp->ipv4.id = rx_icmp->ipv4.id; 336 | tx_icmp->ipv4.flags = rx_icmp->ipv4.flags; 337 | tx_icmp->ipv4.ttl = rx_icmp->ipv4.ttl; 338 | tx_icmp->ipv4.protocol = rx_icmp->ipv4.protocol; 339 | tx_icmp->ipv4.checksum = rx_icmp->ipv4.checksum; // No need to recalculate checksum 340 | memcpy(tx_icmp->ipv4.src_ip, rx_icmp->ipv4.dest_ip, 4); 341 | memcpy(tx_icmp->ipv4.dest_ip, rx_icmp->ipv4.src_ip, 4); 342 | // ICMP 343 | tx_icmp->type = ICMP_ECHO_REPLY; 344 | tx_icmp->code = rx_icmp->code; 345 | tx_icmp->checksum = 0; 346 | tx_icmp->id = rx_icmp->id; 347 | tx_icmp->sequence = rx_icmp->sequence; 348 | tx_icmp->timestamp = rx_icmp->timestamp; 349 | memcpy (tx_icmp->data, rx_icmp->data, (swap16(rx_icmp->ipv4.total_length)-20-16)); // IP length - IPv4 header - ICMP header 350 | tx_icmp->checksum = checksum(&tosend[34], recv_packet_len-14-20); // Frame length - MAC header - IPv4 header 351 | // Send the reply 352 | net_send(tosend, recv_packet_len); 353 | } 354 | } 355 | else if (rx_icmp->type == ICMP_ECHO_REPLY) 356 | { 357 | // printf("Reply"); 358 | } 359 | else 360 | { 361 | // printf("Unknown ICMP packet"); 362 | } 363 | } 364 | else if(rx_ipv4->protocol == PROTOCOL_IP_TCP) 365 | { 366 | // printf("TCP"); 367 | tcp_packet* rx_tcp = (tcp_packet*)buffer; 368 | if (rx_tcp->flags == TCP_SYN) 369 | { 370 | // printf(" - SYN"); 371 | tcp_packet* tx_tcp = (tcp_packet*)tosend; 372 | memcpy((void*)tosend, (void*)buffer, ETH_FRAME_LEN); // make a copy of the original frame 373 | // Ethernet 374 | memcpy(tx_tcp->ipv4.ethernet.dest_mac, rx_tcp->ipv4.ethernet.src_mac, 6); 375 | memcpy(tx_tcp->ipv4.ethernet.src_mac, src_MAC, 6); 376 | tx_tcp->ipv4.ethernet.type = swap16(ETHERTYPE_IPv4); 377 | // IPv4 378 | tx_tcp->ipv4.version = rx_tcp->ipv4.version; 379 | tx_tcp->ipv4.dsf = rx_tcp->ipv4.dsf; 380 | tx_tcp->ipv4.total_length = rx_tcp->ipv4.total_length; 381 | tx_tcp->ipv4.id = rx_tcp->ipv4.id; 382 | tx_tcp->ipv4.flags = rx_tcp->ipv4.flags; 383 | tx_tcp->ipv4.ttl = rx_tcp->ipv4.ttl; 384 | tx_tcp->ipv4.protocol = rx_tcp->ipv4.protocol; 385 | tx_tcp->ipv4.checksum = 0; 386 | memcpy(tx_tcp->ipv4.src_ip, rx_tcp->ipv4.dest_ip, 4); 387 | memcpy(tx_tcp->ipv4.dest_ip, rx_tcp->ipv4.src_ip, 4); 388 | tx_tcp->ipv4.checksum = checksum(&tosend[14], 20); 389 | // TCP 390 | tx_tcp->src_port = rx_tcp->dest_port; 391 | tx_tcp->dest_port = rx_tcp->src_port; 392 | tx_tcp->seqnum = rx_tcp->seqnum; 393 | tx_tcp->acknum = swap32(swap32(rx_tcp->seqnum)+1); 394 | tx_tcp->data_offset = rx_tcp->data_offset; 395 | tx_tcp->flags = TCP_SYN|TCP_ACK; 396 | tx_tcp->window = rx_tcp->window; 397 | tx_tcp->checksum = 0; 398 | tx_tcp->urg_pointer = rx_tcp->urg_pointer; 399 | tx_tcp->checksum = checksum_tcp(&tosend[34], recv_packet_len-34, PROTOCOL_IP_TCP, recv_packet_len-34); 400 | // Send the reply 401 | net_send(tosend, recv_packet_len); 402 | } 403 | else if (rx_tcp->flags == TCP_ACK) 404 | { 405 | // printf(" - ACK"); 406 | // Ignore these for now. 407 | } 408 | else if (rx_tcp->flags == (TCP_PSH|TCP_ACK)) 409 | { 410 | // printf(" - PSH"); 411 | tcp_packet* tx_tcp = (tcp_packet*)tosend; 412 | memcpy((void*)tosend, (void*)buffer, ETH_FRAME_LEN); // make a copy of the original frame 413 | // Ethernet 414 | memcpy(tx_tcp->ipv4.ethernet.dest_mac, rx_tcp->ipv4.ethernet.src_mac, 6); 415 | memcpy(tx_tcp->ipv4.ethernet.src_mac, src_MAC, 6); 416 | tx_tcp->ipv4.ethernet.type = swap16(ETHERTYPE_IPv4); 417 | // IPv4 418 | tx_tcp->ipv4.version = rx_tcp->ipv4.version; 419 | tx_tcp->ipv4.dsf = rx_tcp->ipv4.dsf; 420 | tx_tcp->ipv4.total_length = swap16(52); 421 | tx_tcp->ipv4.id = rx_tcp->ipv4.id; 422 | tx_tcp->ipv4.flags = rx_tcp->ipv4.flags; 423 | tx_tcp->ipv4.ttl = rx_tcp->ipv4.ttl; 424 | tx_tcp->ipv4.protocol = rx_tcp->ipv4.protocol; 425 | tx_tcp->ipv4.checksum = 0; 426 | memcpy(tx_tcp->ipv4.src_ip, rx_tcp->ipv4.dest_ip, 4); 427 | memcpy(tx_tcp->ipv4.dest_ip, rx_tcp->ipv4.src_ip, 4); 428 | tx_tcp->ipv4.checksum = checksum(&tosend[14], 20); 429 | // TCP 430 | tx_tcp->src_port = rx_tcp->dest_port; 431 | tx_tcp->dest_port = rx_tcp->src_port; 432 | tx_tcp->seqnum = rx_tcp->seqnum; 433 | tx_tcp->acknum = swap32(swap32(rx_tcp->seqnum)+(recv_packet_len-14-20-32)); // Add the bytes received 434 | tx_tcp->data_offset = rx_tcp->data_offset; 435 | tx_tcp->flags = TCP_ACK; 436 | tx_tcp->window = rx_tcp->window; 437 | tx_tcp->checksum = 0; 438 | tx_tcp->urg_pointer = rx_tcp->urg_pointer; 439 | tx_tcp->checksum = checksum_tcp(&tosend[34], 32, PROTOCOL_IP_TCP, 32); 440 | // Send the reply 441 | net_send(tosend, 66); 442 | // Send the webpage 443 | tx_tcp->ipv4.total_length = swap16(52+strlen(webpage)); 444 | tx_tcp->ipv4.checksum = 0; 445 | tx_tcp->ipv4.checksum = checksum(&tosend[14], 20); 446 | tx_tcp->flags = TCP_PSH|TCP_ACK; 447 | tx_tcp->checksum = 0; 448 | memcpy((char*)tosend+66, (char*)webpage, strlen(webpage)); 449 | tx_tcp->checksum = checksum_tcp(&tosend[34], 32+strlen(webpage), PROTOCOL_IP_TCP, 32+strlen(webpage)); 450 | net_send(tosend, 66+strlen(webpage)); 451 | // Disconnect the client 452 | tx_tcp->ipv4.total_length = swap16(52); 453 | tx_tcp->ipv4.checksum = 0; 454 | tx_tcp->ipv4.checksum = checksum(&tosend[14], 20); 455 | tx_tcp->seqnum = swap32(swap32(tx_tcp->seqnum)+strlen(webpage)); 456 | tx_tcp->flags = TCP_FIN|TCP_ACK; 457 | tx_tcp->checksum = 0; 458 | tx_tcp->checksum = checksum_tcp(&tosend[34], 32, PROTOCOL_IP_TCP, 32); 459 | net_send(tosend, 66); 460 | } 461 | else if (rx_tcp->flags == (TCP_FIN|TCP_ACK)) 462 | { 463 | // printf(" - FIN"); 464 | tcp_packet* tx_tcp = (tcp_packet*)tosend; 465 | memcpy((void*)tosend, (void*)buffer, ETH_FRAME_LEN); // make a copy of the original frame 466 | // Ethernet 467 | memcpy(tx_tcp->ipv4.ethernet.dest_mac, rx_tcp->ipv4.ethernet.src_mac, 6); 468 | memcpy(tx_tcp->ipv4.ethernet.src_mac, src_MAC, 6); 469 | tx_tcp->ipv4.ethernet.type = swap16(ETHERTYPE_IPv4); 470 | // IPv4 471 | tx_tcp->ipv4.version = rx_tcp->ipv4.version; 472 | tx_tcp->ipv4.dsf = rx_tcp->ipv4.dsf; 473 | tx_tcp->ipv4.total_length = swap16(52); 474 | tx_tcp->ipv4.id = rx_tcp->ipv4.id; 475 | tx_tcp->ipv4.flags = rx_tcp->ipv4.flags; 476 | tx_tcp->ipv4.ttl = rx_tcp->ipv4.ttl; 477 | tx_tcp->ipv4.protocol = rx_tcp->ipv4.protocol; 478 | tx_tcp->ipv4.checksum = 0; 479 | memcpy(tx_tcp->ipv4.src_ip, rx_tcp->ipv4.dest_ip, 4); 480 | memcpy(tx_tcp->ipv4.dest_ip, rx_tcp->ipv4.src_ip, 4); 481 | tx_tcp->ipv4.checksum = checksum(&tosend[14], 20); 482 | // TCP 483 | tx_tcp->src_port = rx_tcp->dest_port; 484 | tx_tcp->dest_port = rx_tcp->src_port; 485 | tx_tcp->seqnum = rx_tcp->acknum; 486 | tx_tcp->acknum = swap32(swap32(rx_tcp->seqnum)+1); 487 | tx_tcp->data_offset = rx_tcp->data_offset; 488 | tx_tcp->flags = TCP_ACK; 489 | tx_tcp->window = rx_tcp->window; 490 | tx_tcp->checksum = 0; 491 | tx_tcp->urg_pointer = rx_tcp->urg_pointer; 492 | tx_tcp->checksum = checksum_tcp(&tosend[34], 32, PROTOCOL_IP_TCP, 32); 493 | // Send the reply 494 | net_send(tosend, 66); 495 | } 496 | // printf("\n"); 497 | } 498 | else if (rx_ipv4->protocol == PROTOCOL_IP_UDP) 499 | { 500 | // TODO - UDP 501 | } 502 | else 503 | { 504 | // printf("Unknown protocol"); 505 | } 506 | } 507 | else if (swap16(rx->type) == ETHERTYPE_IPv6) 508 | { 509 | // TODO - IPv6 510 | } 511 | } 512 | } 513 | 514 | #if defined(BAREMETAL) 515 | b_output("\n", 1); 516 | #else 517 | printf("\n"); 518 | #endif 519 | net_exit(); 520 | return 0; 521 | } 522 | 523 | 524 | /* checksum - Calculate a checksum value */ 525 | // Returns 16-bit checksum 526 | u16 checksum(u8* data, u16 bytes) 527 | { 528 | u32 sum = 0; 529 | u16 i; 530 | 531 | for (i=0; i> 16) // Fold total to 16-bits 538 | sum = (sum & 0xFFFF) + (sum >> 16); 539 | 540 | return ~sum; // Return 1's complement 541 | } 542 | 543 | 544 | /* checksum_tcp - Calculate a TCP checksum value */ 545 | // Returns 16-bit checksum 546 | u16 checksum_tcp(u8* data, u16 bytes, u16 protocol, u16 length) 547 | { 548 | u32 sum = 0; 549 | u16 i; 550 | data -= 8; // Start at the source and dest IPs 551 | bytes += 8; 552 | 553 | for (i=0; i> 16) // Fold total to 16-bits 563 | sum = (sum & 0xFFFF) + (sum >> 16); 564 | 565 | return ~sum; // Return 1's complement 566 | } 567 | 568 | 569 | /* net_init - Initialize a raw socket */ 570 | #if defined(BAREMETAL) 571 | int net_init() 572 | #else 573 | int net_init(char *interface) 574 | #endif 575 | { 576 | #if defined(BAREMETAL) 577 | /* Populate the MAC Address */ 578 | /* Pulls the MAC from the OS sys var table... so gross */ 579 | char * os_MAC = (void*)0x110050; 580 | src_MAC[0] = os_MAC[0]; 581 | src_MAC[1] = os_MAC[1]; 582 | src_MAC[2] = os_MAC[2]; 583 | src_MAC[3] = os_MAC[3]; 584 | src_MAC[4] = os_MAC[4]; 585 | src_MAC[5] = os_MAC[5]; 586 | #else 587 | /* Open a socket in raw mode */ 588 | s = socket(PF_PACKET, SOCK_RAW, htons(ETH_P_ALL)); 589 | if (s == -1) 590 | { 591 | printf("Error: Could not open socket! Check your permissions.\n"); 592 | exit(1); 593 | } 594 | 595 | /* Which interface are we using? */ 596 | memset(&ifr, 0, sizeof(struct ifreq)); 597 | strncpy(ifr.ifr_name, interface, IFNAMSIZ); 598 | 599 | /* Does that interface exist? */ 600 | if (ioctl(s, SIOCGIFINDEX, &ifr) == -1) 601 | { 602 | printf("Interface '%s' does not exist.\n", interface); 603 | close(s); 604 | exit(1); 605 | } 606 | 607 | /* Is that interface up? */ 608 | ioctl(s, SIOCGIFFLAGS, &ifr); 609 | if ((ifr.ifr_flags & IFF_UP) == 0) 610 | { 611 | printf("Interface '%s' is down.\n", interface); 612 | close(s); 613 | exit(1); 614 | } 615 | 616 | /* Configure the port for non-blocking */ 617 | if (-1 == fcntl(s, F_SETFL, O_NONBLOCK)) 618 | { 619 | printf("fcntl (NonBlocking) Warning\n"); 620 | close(s); 621 | exit(1); 622 | } 623 | 624 | /* Get the MAC address */ 625 | ioctl(s, SIOCGIFHWADDR, &ifr); 626 | for (c=0; c<6; c++) 627 | { 628 | src_MAC[c] = (unsigned char)ifr.ifr_ifru.ifru_hwaddr.sa_data[c]; // This works... but WTF 629 | } 630 | 631 | /* Write in the structure again */ 632 | ioctl(s, SIOCGIFINDEX, &ifr); 633 | 634 | /* Configure the rest of what we need */ 635 | memset(&sa, 0, sizeof (sa)); 636 | sa.sll_family = AF_PACKET; 637 | sa.sll_ifindex = ifr.ifr_ifindex; 638 | sa.sll_protocol = htons(ETH_P_ALL); 639 | 640 | int test_var = 1; 641 | unsigned char *test_endian = (unsigned char*)&test_var; 642 | 643 | if (test_endian[0] == 0x00) 644 | { 645 | printf("Big Endian system detected! This program will fail horribly."); 646 | return -1; 647 | } 648 | 649 | #endif 650 | /* We should now have a working port to send/recv raw frames */ 651 | return 0; 652 | } 653 | 654 | 655 | /* net_exit - Clean up and exit */ 656 | int net_exit() 657 | { 658 | #if !defined(BAREMETAL) 659 | close(s); 660 | #endif 661 | return 0; 662 | } 663 | 664 | /* net_send - Send a raw Ethernet packet */ 665 | // Wrapper for OS send function 666 | // Returns number of bytes sent 667 | int net_send(unsigned char* data, unsigned int bytes) 668 | { 669 | #if defined(BAREMETAL) 670 | b_net_tx(data, bytes, 0); 671 | return bytes; 672 | #else 673 | return (sendto(s, data, bytes, 0, (struct sockaddr *)&sa, sizeof (sa))); 674 | #endif 675 | } 676 | 677 | 678 | /* net_recv - Receive a raw Ethernet packet */ 679 | // Wrapper for OS recv function 680 | // Returns number of bytes read 681 | int net_recv(unsigned char* data) 682 | { 683 | #if defined(BAREMETAL) 684 | return b_net_rx(data, 0); 685 | #else 686 | return (recvfrom(s, data, ETH_FRAME_LEN, 0, 0, 0)); 687 | #endif 688 | } 689 | 690 | 691 | /* swap16 - Change endianness on a 16-bit value */ 692 | // x86-64 uses little-endian while IP uses big-endian 693 | u16 swap16(u16 in) 694 | { 695 | u16 out = in<<8 | ((in&0xff00)>>8); 696 | return out; 697 | } 698 | 699 | 700 | /* swap32 - Change endianness on a 32-bit value */ 701 | // x86-64 uses little-endian while IP uses big-endian 702 | u32 swap32(u32 in) 703 | { 704 | u32 out = in<<24 | ((in&0xff00)<<8) | ((in&0xff0000)>>8) | ((in&0xff000000)>>24); 705 | return out; 706 | } 707 | 708 | #ifdef BAREMETAL 709 | void* memset(void* s, int c, int n) 710 | { 711 | char* _src; 712 | 713 | _src = (char*)s; 714 | 715 | while (n--) { 716 | *_src++ = c; 717 | } 718 | 719 | return s; 720 | } 721 | 722 | void* memcpy(void* d, const void* s, int n) 723 | { 724 | char* dest; 725 | char* src; 726 | 727 | dest = (char*)d; 728 | src = (char*)s; 729 | 730 | while (n--) { 731 | *dest++ = *src++; 732 | } 733 | 734 | return d; 735 | } 736 | 737 | int strlen(const char* s) 738 | { 739 | int r = 0; 740 | 741 | for(; *s++ != 0; r++) { } 742 | 743 | return r; 744 | } 745 | #endif 746 | 747 | /* EOF */ 748 | --------------------------------------------------------------------------------