Nilorea Library
C utilities for networking, threading, graphics
Loading...
Searching...
No Matches
ex_ssrf.c

n_ssrf regression: public addresses pass, private/reserved are blocked, and a private IPv4 smuggled inside IPv6 is still blocked.

n_ssrf regression: public addresses pass, private/reserved are blocked, and a private IPv4 smuggled inside IPv6 is still blocked.

Author
Castagnier Mickael
Version
1.0
/*
* 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) {
/* 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 */
n_log(LOG_ERR, "FAIL: NULL must be rejected");
}
/* 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;
n_log(LOG_ERR, "FAIL: ::1 must be blocked");
}
if (!n_ssrf_ipv6_allowed(pub)) {
n_log(LOG_ERR, "FAIL: a public v6 should be allowed");
}
}
/* 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_log(LOG_ERR, "FAIL: a private IPv4 smuggled in IPv6 must block");
}
}
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;
}
static int failures
Definition ex_atlas.c:51
int main(void)
Definition ex_atlas.c:117
#define NO4(a, b, c, d)
Definition ex_ssrf.c:45
#define OK4(a, b, c, d)
Definition ex_ssrf.c:35
#define n_log(__LEVEL__,...)
Logging function wrapper to get line and func.
Definition n_log.h:113
#define LOG_ERR
error conditions
Definition n_log.h:100
void set_log_level(const int log_level)
Set the global log level value ( static int LOG_LEVEL ).
Definition n_log.c:123
#define LOG_NOTICE
normal but significant condition
Definition n_log.h:104
Generic log system.
int n_ssrf_ipv4_allowed(const uint8_t ip[4])
classify an IPv4 address as safe-to-connect or not
Definition n_ssrf.c:60
int n_ssrf_ipv6_allowed(const uint8_t ip[16])
classify an IPv6 address as safe-to-connect or not
Definition n_ssrf.c:101
SSRF address guard: is a resolved IP a public, routable unicast address?