7 ex__ssrf_8c
gullradriel edited this page 2026-10-29 20:54:40 +01:00

examples/ex_ssrf.c

Functions

Name
int main(void )

Attributes

Name
int failures

Defines

Name
OK4(a, b, c, d)
NO4(a, b, c, d)

Functions Documentation

function main

int main(
    void 
)

Attributes Documentation

variable failures

static int failures = 0;

Macros Documentation

define OK4

#define OK4(
    a,
    b,
    c,
    d
)
do {                                                                   \
    const uint8_t ip[4] = {a, b, c, d};                                \
    if (!n_ssrf_ipv4_allowed(ip)) {                                    \
        n_log(LOG_ERR, "FAIL: %d.%d.%d.%d should be allowed", a, b, c, \
              d);                                                      \
        failures++;                                                    \
    }                                                                  \
} while (0)

define NO4

#define NO4(
    a,
    b,
    c,
    d
)
do {                                                                   \
    const uint8_t ip[4] = {a, b, c, d};                                \
    if (n_ssrf_ipv4_allowed(ip)) {                                     \
        n_log(LOG_ERR, "FAIL: %d.%d.%d.%d should be blocked", a, b, c, \
              d);                                                      \
        failures++;                                                    \
    }                                                                  \
} while (0)

Source code

/*
 * Nilorea Library
 * Copyright (C) 2005-2026 Castagnier Mickael
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 * implied. See the License for the specific language governing
 * permissions and limitations under the License.
 *
 * SPDX-License-Identifier: Apache-2.0
 */


#include "nilorea/n_log.h"
#include "nilorea/n_ssrf.h"

#include <string.h>

static int failures = 0;

#define OK4(a, b, c, d)                                                    \
    do {                                                                   \
        const uint8_t ip[4] = {a, b, c, d};                                \
        if (!n_ssrf_ipv4_allowed(ip)) {                                    \
            n_log(LOG_ERR, "FAIL: %d.%d.%d.%d should be allowed", a, b, c, \
                  d);                                                      \
            failures++;                                                    \
        }                                                                  \
    } while (0)

#define NO4(a, b, c, d)                                                    \
    do {                                                                   \
        const uint8_t ip[4] = {a, b, c, d};                                \
        if (n_ssrf_ipv4_allowed(ip)) {                                     \
            n_log(LOG_ERR, "FAIL: %d.%d.%d.%d should be blocked", a, b, c, \
                  d);                                                      \
            failures++;                                                    \
        }                                                                  \
    } while (0)

int main(void) {
    set_log_level(LOG_NOTICE);

    /* public unicast: allowed */
    OK4(8, 8, 8, 8);
    OK4(1, 1, 1, 1);
    OK4(93, 184, 216, 34);

    /* private / reserved / special: blocked */
    NO4(0, 0, 0, 0);         /* this host                    */
    NO4(10, 0, 0, 1);        /* RFC1918                      */
    NO4(127, 0, 0, 1);       /* loopback                     */
    NO4(169, 254, 169, 254); /* link-local metadata endpoint */
    NO4(172, 16, 0, 1);      /* RFC1918                      */
    NO4(192, 168, 1, 1);     /* RFC1918                      */
    NO4(100, 64, 0, 1);      /* CGNAT                        */
    NO4(224, 0, 0, 1);       /* multicast                    */
    NO4(255, 255, 255, 255); /* broadcast/reserved           */

    /* NULL is rejected */
    if (n_ssrf_ipv4_allowed(NULL) || n_ssrf_ipv6_allowed(NULL)) {
        n_log(LOG_ERR, "FAIL: NULL must be rejected");
        failures++;
    }

    /* IPv6: loopback blocked, a public v6 allowed */
    {
        uint8_t lo[16] = {0};
        uint8_t pub[16] = {0x26, 0x06, 0x47, 0x00}; /* 2606:4700::  public */
        lo[15] = 1;
        if (n_ssrf_ipv6_allowed(lo)) {
            n_log(LOG_ERR, "FAIL: ::1 must be blocked");
            failures++;
        }
        if (!n_ssrf_ipv6_allowed(pub)) {
            n_log(LOG_ERR, "FAIL: a public v6 should be allowed");
            failures++;
        }
    }

    /* the smuggling cases: a private IPv4 wrapped in IPv6 must stay blocked */
    {
        /* ::ffff:127.0.0.1  (IPv4-mapped loopback) */
        uint8_t mapped[16] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff,
                              127, 0, 0, 1};
        /* 64:ff9b::a00:1  (NAT64 wrapping 10.0.0.1) */
        uint8_t nat64[16] = {0x00, 0x64, 0xff, 0x9b, 0, 0, 0, 0, 0, 0, 0, 0,
                             10, 0, 0, 1};
        /* 2002:c0a8:0101::  (6to4 wrapping 192.168.1.1) */
        uint8_t sixto4[16] = {0x20, 0x02, 192, 168, 1, 1};
        if (n_ssrf_ipv6_allowed(mapped) || n_ssrf_ipv6_allowed(nat64) ||
            n_ssrf_ipv6_allowed(sixto4)) {
            n_log(LOG_ERR, "FAIL: a private IPv4 smuggled in IPv6 must block");
            failures++;
        }
    }

    if (failures) {
        n_log(LOG_ERR, "ex_ssrf: %d failure(s)", failures);
        return 1;
    }
    n_log(LOG_NOTICE, "ex_ssrf: all checks passed");
    return 0;
}