Day 5 of 5
⏱ ~60 minutes
C Programming in 5 Days — Day 5

C in the Real World: Networking & Security

C powers the networking stack, web servers, and security tools. Today you write a TCP server, explore socket programming, and examine how real-world C security vulnerabilities arise and how modern tooling prevents them.

BSD Sockets

socket() creates a network endpoint. bind() assigns an address. listen() marks it passive. accept() waits for connections. connect() initiates a connection. send()/recv() transfer data. Close with close(). The socket API is identical across Linux, macOS, and BSD — it has not changed fundamentally since 4.2 BSD (1983). Every network program in any language ultimately calls these same kernel interfaces.

Secure Coding Practices

The most common C vulnerabilities: format string bugs (printf(user_input) instead of printf('%s', user_input) — attacker controls format specifiers), integer overflow (int a = INT_MAX; a++ is undefined behavior), off-by-one errors (<=n should be

Modern C: C11 and C23

C11 added: _Atomic types for lock-free programming, _Static_assert for compile-time checks, thread_local storage, anonymous structs/unions, and improved Unicode support. C23 (ratified 2023) adds: typeof(), #embed for binary file inclusion, nullptr literal (replacing NULL for pointers), bool/true/false as keywords, constexpr for constants. Use -std=c23 or -std=c11 with recent gcc/clang.

c
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <arpa/inet.h>
#include <sys/socket.h>

#define PORT 8080
#define BUFSIZE 4096

int main(void) {
    int server = socket(AF_INET, SOCK_STREAM, 0);
    int opt = 1;
    setsockopt(server, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));

    struct sockaddr_in addr = {
        .sin_family = AF_INET,
        .sin_port   = htons(PORT),
        .sin_addr   = {INADDR_ANY}
    };
    bind(server, (struct sockaddr*)&addr, sizeof(addr));
    listen(server, 10);
    printf("Listening on :%d\n", PORT);

    while (1) {
        int client = accept(server, NULL, NULL);
        char buf[BUFSIZE];
        ssize_t n = recv(client, buf, sizeof(buf)-1, 0);
        if (n > 0) {
            buf[n] = '\0';
            char resp[] = "HTTP/1.1 200 OK\r\nContent-Length: 13\r\n\r\nHello, World!";
            send(client, resp, sizeof(resp)-1, 0);
        }
        close(client);
    }
}
💡
Call setsockopt(SO_REUSEADDR) before bind() so your server restarts quickly without 'Address already in use' errors. Without it, you wait 60 seconds for the OS to reclaim the port after each restart.
📝 Day 5 Exercise
Build a Multi-Client TCP Server
  1. Compile and run the HTTP server above
  2. Test it: curl http://localhost:8080/ should return 'Hello, World!'
  3. Add fork() to handle each connection in a separate process
  4. Add logging: print the client IP and bytes received for each connection
  5. Run it under AFL++: afl-fuzz -i inputs/ -o findings/ -- ./server

Day 5 Summary

  • BSD socket API: socket, bind, listen, accept, connect, send/recv, close
  • Format string bugs (printf(buf)) are critical vulnerabilities — always use printf('%s', buf)
  • Integer overflow is undefined behavior in C — use explicit range checks
  • AddressSanitizer (-fsanitize=address) and AFL++ catch memory bugs before production
  • C11 added atomics, static_assert; C23 adds typeof, nullptr, constexpr
Challenge

Write a concurrent key-value store server in C: accepts TCP connections, parses 'SET key value' and 'GET key' commands, stores data in a hash table, and handles 10 simultaneous clients using threads with proper mutex locking.

Finished this lesson?