365 Days of Code - Day 049

Project Status

ProjectLanguageStatusDue DateLatest Update
Personal WebsiteHugoOngoingNoneThe site is live. Continuous improvements ongoing.
Laravel From ScratchLaravel (PHP)In-Progress2026-03-31Episode 8
PRMLaravel (PHP)In-Progress2026-03-31Working alongside other Laravel projects.
Client Website (J.L.)Laravel (PHP)In-Progress2026-03-31Working alongside other Laravel projects.
Project EulerCOngoingNoneWorking on P25. BigInt (AI gen) was a waste of time, need to rewrite
Practice JavaJavaPausedNoneInstalled, need to find a good project.
Practice PythonPythonPausedNoneInstalled, need to find a good project.
Learn GoGoPausedNoneInstalled, work on LDAP Injector from ippsec.
Learn RustRustHaven’t StartedNoneInstalled, will try network protocols after finishing in C and Zig.
Learn ElixirElixirHaven’t StartedNoneInstalled, need a good tutorial project.
Learn HaskellHaskellHaven’t StartedNoneInstalled, need a good tutorial project.
Learn ZigZigHaven’t StartedNoneInstalled, will try network protocols after finishing in C.
Linux+N/AIn-Progress2026-03-31Reading Chapter 4.
Cyber Quest 2026N/AIn-Progress2026-02-28Finished quiz 1 with 75%.
Operating SystemsN/AIn-Progress2026-03-31Reading Chapter 4: Abstraction
Grey-Hat HackingVariousIn-Progress2026-03-31Reading Chapter 8: Threat Hunting Lab
PHP Time TrackerPHPBeta FinishedNoneWorking on a basic level.
HTTP Status Code ReaderCComplete2026-02-18Complete.
ZSH Configurationbash/zshCompleteNoneSort of an ongoing process, but complete for now. Works good.
Network ProtocolsCIn-ProgressNoneWorking on V3, implementing IPv6.
Discinox WebsiteHTML, CSS, JSComplete2026-03-04The site is live.
DiroffTech WebsiteHTML, CSS, JSComplete2026-03-05The site is live. git-lfs needs to be initialized for images.
Automate BackupsbashComplete2026-03-08Backups done.

IP (6) Protocol From Scratch

I got back to the network code programming today, with a refactoring of my V1 and V2 code from IP Protocol From Scratch (opens in a new tab). In V3, I’m separating the logic into proper header files, and building up a library that is more generalized. I’m also performing my first implementation of IPv6 (opens in a new tab). At first I was thrown off because the first 4 bytes of the IPv6 header did not align with uint8 or uint16, before I realized that a 32-bit member would perfectly capture the first fields of the header: uint32_t version_class_flow;. The IP Version takes the first 4 bits, the Traffic Class takes the middle 8 bits, and the Flow Label takes the last 20 bits. With my experience in packing and shifting bits around in the first two versions, this shouldn’t be too bad.

  • ip_stack.h
c
/**
 * ip_stack.h
 *
 * @brief RFC implementation of the IP protocol
 * IPv4: RFC 791
 * IPv6: RFC 8200
 */

#ifndef IP_STACK_H
#define IP_STACK_H

#include <stdint.h>

/**
 * @enum ip_version
 * @brief Version identifiers.
 */
enum ip_version
{
    IPV4 = 4,
    IPV6 = 6
};

/**
 * @enum ip_protocol
 * @brief Upper-layer protocol identifiers.
 */
enum ip_protocol
{
    IP_PROTO_ICMP = 1 /** Internet Control Message Protocol */
};

/**
 * @struct ipv4_header
 * @brief 20-byte IPv4 header, packed wire layout, without options.
 *
 * @ref RFC 791
 */
struct ipv4_header
{
    uint8_t version_ihl;     /** IP Version (4 bits) + Internet Header Length (4 bits) */
    uint8_t type_of_service; /** DSCP+ECN - See RFC 2474 (DSCP), RFC 3168 (ECN) and their respective updates */
    uint16_t total_length;   /** Length of complete datagram, in octets. Absolute Max: 65535, Recommended Max: 576 */
    uint16_t id;             /** Aids in reassembly of fragments */
    uint16_t flags_offset;   /** Flags (3 bits) + Fragment Offset (13 bits) */
    uint8_t ttl;             /** Time to Live a.k.a. hop count */
    uint8_t protocol;        /** Upper-layer protocol id */
    uint16_t checksum;       /** Ones' complement checksum of all 16-bit words in the header */
    uint32_t src;            /** Source address */
    uint32_t dst;            /** Destination address */
} __attribute__((packed));

/**
 * @struct ipv6_header
 * @brief 40-byte IPv6 header, packed wire layout, without extensions.
 *
 * @ref RFC 8200
 */
struct ipv6_header
{
    uint32_t version_class_flow; /** IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /** Length of the packet following this header (extension headers + payload) */
    uint8_t next_header;         /** ID of the type of header following this header */
    uint8_t hop_limit;           /** Hop limit (TTL in IPv4) */
    uint8_t src[16];             /** Source address (128-bit) */
    uint8_t dst[16];             /** Destination address (128-bit) */
} __attribute__((packed));

#endif /* IP_STACK_H */
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/**
 * ip_stack.h
 *
 * @brief RFC implementation of the IP protocol
 * IPv4: RFC 791
 * IPv6: RFC 8200
 */

#ifndef IP_STACK_H
#define IP_STACK_H

#include <stdint.h>

/**
 * @enum ip_version
 * @brief Version identifiers.
 */
enum ip_version
{
    IPV4 = 4,
    IPV6 = 6
};

/**
 * @enum ip_protocol
 * @brief Upper-layer protocol identifiers.
 */
enum ip_protocol
{
    IP_PROTO_ICMP = 1 /** Internet Control Message Protocol */
};

/**
 * @struct ipv4_header
 * @brief 20-byte IPv4 header, packed wire layout, without options.
 *
 * @ref RFC 791
 */
struct ipv4_header
{
    uint8_t version_ihl;     /** IP Version (4 bits) + Internet Header Length (4 bits) */
    uint8_t type_of_service; /** DSCP+ECN - See RFC 2474 (DSCP), RFC 3168 (ECN) and their respective updates */
    uint16_t total_length;   /** Length of complete datagram, in octets. Absolute Max: 65535, Recommended Max: 576 */
    uint16_t id;             /** Aids in reassembly of fragments */
    uint16_t flags_offset;   /** Flags (3 bits) + Fragment Offset (13 bits) */
    uint8_t ttl;             /** Time to Live a.k.a. hop count */
    uint8_t protocol;        /** Upper-layer protocol id */
    uint16_t checksum;       /** Ones' complement checksum of all 16-bit words in the header */
    uint32_t src;            /** Source address */
    uint32_t dst;            /** Destination address */
} __attribute__((packed));

/**
 * @struct ipv6_header
 * @brief 40-byte IPv6 header, packed wire layout, without extensions.
 *
 * @ref RFC 8200
 */
struct ipv6_header
{
    uint32_t version_class_flow; /** IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /** Length of the packet following this header (extension headers + payload) */
    uint8_t next_header;         /** ID of the type of header following this header */
    uint8_t hop_limit;           /** Hop limit (TTL in IPv4) */
    uint8_t src[16];             /** Source address (128-bit) */
    uint8_t dst[16];             /** Destination address (128-bit) */
} __attribute__((packed));

#endif /* IP_STACK_H */

A Quick Aside for Doxygen

As you can see, I’ve also been writing up Doxygen (opens in a new tab)-style comments for everything. I’ll be incorporating that into my workflow as well.

bash
sudo apt install doxygen doxygen-doc doxygen2man
1
sudo apt install doxygen doxygen-doc doxygen2man

The default usage of Doxygen was very simple.

  1. Generate a Doxyfile
  2. Generate the documentation
  3. View the HTML
bash
doxygen -g
doxygen Doxyfile
cd html
python3 -m http.server 3000
1
2
3
4
doxygen -g
doxygen Doxyfile
cd html
python3 -m http.server 3000

Doxygen generally expects the comment to be before the thing to be documented. In the case of in-line comments on struct members, a < character must be added for the documentation engine to assign the comment properly.

c
struct ipv6_header
{
    uint32_t version_class_flow; /**< IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /**< Length of the packet following this header (extension headers + payload) */
<snip>
1
2
3
4
5
struct ipv6_header
{
    uint32_t version_class_flow; /**< IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /**< Length of the packet following this header (extension headers + payload) */
<snip>

Separate the Protocols

After getting both IP headers in place, I started to think a bit more about the architecture we were developing. ICMP for IPv4 and IPv6 are quite different, and will be placed in their own files. I think it makes sense that if we are developing a two separate stacks for ICMP, we should do the same for IP. There is no reason why the IPv4 and IPv6 protocols cannot exist in their own header files. There is only one issue, which is easily rectified. There are some shared parameters between IPv4 and IPv6, such as the protocol identifiers (opens in a new tab). The IANA has created a list of assigned internet protocol numbers that both protocols use. To avoid duplicating an enum, another file, ip_common.h is added, which holds shared data.

  • ip_common.h
c
/**
 * ip_common.h
 *
 * @brief Shared components and parameters for IPv4 and IPv6 protocols
 * IPv4: RFC 791
 * IPv6: RFC 8200
 */

#ifndef IP_COMMON_H
#define IP_COMMON_H

enum ip_version
{
    IPV4 = 4,
    IPV6 = 6
};

enum ip_protocol
{
    IP_PROTO_ICMPV4 = 1,
    IP_PROTO_ICMPV6 = 58
};

#endif /* IP_COMMON_H */
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * ip_common.h
 *
 * @brief Shared components and parameters for IPv4 and IPv6 protocols
 * IPv4: RFC 791
 * IPv6: RFC 8200
 */

#ifndef IP_COMMON_H
#define IP_COMMON_H

enum ip_version
{
    IPV4 = 4,
    IPV6 = 6
};

enum ip_protocol
{
    IP_PROTO_ICMPV4 = 1,
    IP_PROTO_ICMPV6 = 58
};

#endif /* IP_COMMON_H */
  • ipv4.h
c
/**
 * ipv4.h
 *
 * @brief RFC implementation of the IP protocol
 * IPv4: RFC 791
 */

#ifndef IPV4_H
#define IPV4_H

#include <stdint.h>
#include "ip_common.h"

/**
 * @brief Absolute max IPv4 datagram length (header + payload) in octets.
 */
#define IPV4_MAX_PACKET_SIZE 65535

/**
 * @brief Minimum datagram size all hosts must be prepared to accept.
 */
#define IPV4_RECOMMENDED_MTU 576

/**
 * @brief Minimum valid Internet Header Length in 32-bit words (20 bytes).
 */
#define IPV4_MIN_IHL 5

/**
 * @struct ipv4_header
 * @brief 20-byte IPv4 header, packed wire layout, without options.
 *
 * @note RFC 791
 */
struct ipv4_header
{
    uint8_t version_ihl;     /**< IP Version (4 bits) + Internet Header Length (4 bits) */
    uint8_t type_of_service; /**< DSCP+ECN - See RFC 2474 (DSCP), RFC 3168 (ECN) and their respective updates */
    uint16_t total_length;   /**< Length of complete datagram, in octets. Absolute Max: 65535, Recommended Max: 576 */
    uint16_t id;             /**< Aids in reassembly of fragments */
    uint16_t flags_offset;   /**< Flags (3 bits) + Fragment Offset (13 bits) */
    uint8_t ttl;             /**< Time to Live a.k.a. hop count */
    uint8_t protocol;        /**< Upper-layer protocol id */
    uint16_t checksum;       /**< Ones' complement checksum of all 16-bit words in the header */
    uint32_t src;            /**< Source address */
    uint32_t dst;            /**< Destination address */
} __attribute__((packed));

#endif /* IPV4_H */
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
/**
 * ipv4.h
 *
 * @brief RFC implementation of the IP protocol
 * IPv4: RFC 791
 */

#ifndef IPV4_H
#define IPV4_H

#include <stdint.h>
#include "ip_common.h"

/**
 * @brief Absolute max IPv4 datagram length (header + payload) in octets.
 */
#define IPV4_MAX_PACKET_SIZE 65535

/**
 * @brief Minimum datagram size all hosts must be prepared to accept.
 */
#define IPV4_RECOMMENDED_MTU 576

/**
 * @brief Minimum valid Internet Header Length in 32-bit words (20 bytes).
 */
#define IPV4_MIN_IHL 5

/**
 * @struct ipv4_header
 * @brief 20-byte IPv4 header, packed wire layout, without options.
 *
 * @note RFC 791
 */
struct ipv4_header
{
    uint8_t version_ihl;     /**< IP Version (4 bits) + Internet Header Length (4 bits) */
    uint8_t type_of_service; /**< DSCP+ECN - See RFC 2474 (DSCP), RFC 3168 (ECN) and their respective updates */
    uint16_t total_length;   /**< Length of complete datagram, in octets. Absolute Max: 65535, Recommended Max: 576 */
    uint16_t id;             /**< Aids in reassembly of fragments */
    uint16_t flags_offset;   /**< Flags (3 bits) + Fragment Offset (13 bits) */
    uint8_t ttl;             /**< Time to Live a.k.a. hop count */
    uint8_t protocol;        /**< Upper-layer protocol id */
    uint16_t checksum;       /**< Ones' complement checksum of all 16-bit words in the header */
    uint32_t src;            /**< Source address */
    uint32_t dst;            /**< Destination address */
} __attribute__((packed));

#endif /* IPV4_H */
  • ipv6.h
c
/**
 * ipv6.h
 *
 * @brief RFC implementation of the IPv6 protocol
 * IPv6: RFC 8200
 */

#ifndef IPV6_H
#define IPV6_H

#include <stdint.h>
#include "ip_common.h"

/**
 * @brief The absolute minimum link MTU required for any IPv6 network.
 */
#define IPV6_MIN_LINK_MTU 1280

/**
 * @brief The minimum fragment reassembly size all IPv6 nodes must support.
 */
#define IPV6_MIN_REASSEMBLY_SIZE 1500

/**
 * @brief The fixed length of the base IPv6 header in octets (40 bytes).
 */
#define IPV6_BASE_HEADER_LENGTH 40

/**
 * @struct ipv6_header
 * @brief 40-byte IPv6 header, packed wire layout, without extensions.
 *
 * @note RFC 8200
 */
struct ipv6_header
{
    uint32_t version_class_flow; /**< IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /**< Length of the packet following this header (extension headers + payload) */
    uint8_t next_header;         /**< ID of the type of header following this header */
    uint8_t hop_limit;           /**< Hop limit (TTL in IPv4) */
    uint8_t src[16];             /**< Source address (128-bit) */
    uint8_t dst[16];             /**< Destination address (128-bit) */
} __attribute__((packed));

#endif /* IPV6_H */
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
/**
 * ipv6.h
 *
 * @brief RFC implementation of the IPv6 protocol
 * IPv6: RFC 8200
 */

#ifndef IPV6_H
#define IPV6_H

#include <stdint.h>
#include "ip_common.h"

/**
 * @brief The absolute minimum link MTU required for any IPv6 network.
 */
#define IPV6_MIN_LINK_MTU 1280

/**
 * @brief The minimum fragment reassembly size all IPv6 nodes must support.
 */
#define IPV6_MIN_REASSEMBLY_SIZE 1500

/**
 * @brief The fixed length of the base IPv6 header in octets (40 bytes).
 */
#define IPV6_BASE_HEADER_LENGTH 40

/**
 * @struct ipv6_header
 * @brief 40-byte IPv6 header, packed wire layout, without extensions.
 *
 * @note RFC 8200
 */
struct ipv6_header
{
    uint32_t version_class_flow; /**< IP Version (4 bits) + Traffic Class (8 bits) + Flow Label (20 bits) */
    uint16_t payload_length;     /**< Length of the packet following this header (extension headers + payload) */
    uint8_t next_header;         /**< ID of the type of header following this header */
    uint8_t hop_limit;           /**< Hop limit (TTL in IPv4) */
    uint8_t src[16];             /**< Source address (128-bit) */
    uint8_t dst[16];             /**< Destination address (128-bit) */
} __attribute__((packed));

#endif /* IPV6_H */

Related content