Compare commits

..

No commits in common. "master" and "v2.2.3" have entirely different histories.

40 changed files with 78 additions and 3828 deletions

View File

@ -1,27 +1,3 @@
vNEXT:
Added `max_connections` setting to `listen` and
`protocol` configuration; see the
[guide](doc/max_connections.md) for more
information.
(still missing: protocol count for forked protocols
in sslh-[ev|select])
Fix proxyprotocol target field (Thanks to Github user 404-Not-Found)
Fix memory leak in regex probe.
v2.2.4:
Fix CVE-2025-46806 for "Misaligned Memory Accesses in `is_openvpn_protocol()`"
Fix CVE-2025-46807 for "File Descriptor Exhaustion in sslh-select and sslh-ev"
Fix potential parsing of undefined data in syslog
probe (no CVE assigned)
Thanks to Matthias Gerstner of the SUSE security
team for the security review that found these
defects!
v2.2.3:
Reverse older commit: version.h cannot be included
without breaking the build (everything recompiles

View File

@ -22,7 +22,7 @@ MAN=sslh.8.gz # man page name
# itself
ifneq ($(strip $(ENABLE_SANITIZER)),)
CFLAGS_SAN=-fsanitize=address -fsanitize=leak -fsanitize=undefined -fsanitize=alignment
CFLAGS_SAN=-fsanitize=address -fsanitize=leak -fsanitize=undefined
endif
ifneq ($(strip $(COV_TEST)),)
@ -145,8 +145,8 @@ distclean: clean
clean:
rm -f sslh-fork sslh-select $(CONDITIONAL_TARGETS) echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
tags: *.c *.h
ctags *.[ch]
tags:
ctags --globals -T *.[ch]
cscope:
-find . -name "*.[chS]" >cscope.files

View File

@ -30,20 +30,6 @@ Install
Please refer to the [install guide](doc/INSTALL.md).
Security
========
Matthias Gerstner from OpenSUSE has performed a code review
of `sslh` from a security point of view, which revealed a
number of problems, including two CVE. His findings have
already been taken partly into account for the more critical
ones. The [full
review](https://security.opensuse.org/2025/06/13/sslh-denial-of-service-vulnerabilities.html)
is well worth reading if you are using `sslh` in production.
Part of the securing your installation involves configuring
connection limits. This is described in [this
guide](doc/max_connections.md).
Configuration
=============
@ -73,7 +59,6 @@ interfaces. The principle and basic setup is described
[here](doc/simple_transparent_proxy.md), with further
scenarios described [there](doc/scenarios-for-simple-transparent-proxy.md).
There is also a guide to use [podman](doc/podman.md).
Another method uses iptable packet marking features, and is
highly dependent on your network environment and

View File

@ -185,7 +185,6 @@ static int start_listen_inet(struct listen_endpoint *sockfd[], int num_addr, str
(*sockfd)[num_addr-1].socketfd = listen_single_addr(addr, cfg->keepalive, cfg->is_udp);
(*sockfd)[num_addr-1].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
(*sockfd)[num_addr-1].family = AF_INET;
(*sockfd)[num_addr-1].endpoint_cfg = cfg;
print_message(msg_config, "%d:\t%s\t[%s] [%s]\n", (*sockfd)[num_addr-1].socketfd, sprintaddr(buf, sizeof(buf), addr),
cfg->keepalive ? "keepalive" : "",
cfg->is_udp ? "udp" : "");
@ -220,7 +219,6 @@ static int start_listen_unix(struct listen_endpoint *sockfd[], int num_addr, str
(*sockfd)[num_addr-1].socketfd = fd;
(*sockfd)[num_addr-1].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
(*sockfd)[num_addr-1].family = AF_INET;
(*sockfd)[num_addr-1].endpoint_cfg = cfg;
return num_addr;
}
@ -597,37 +595,6 @@ void dump_connection(struct connection *cnx)
}
/* *cnx must have its proto field probed already.
* If required, increment the connection count for this protocol.
* Returns 1 if connection count is exceeded, 0 otherwise */
int inc_proto_connections(struct connection* cnx)
{
cnx->proto->num_connections++;
if (cnx->proto->max_connections_is_present) {
print_message(msg_connections, "Proto %s +1: %d/%d cnx\n",
cnx->proto->name,
cnx->proto->num_connections,
cnx->proto->max_connections);
if (cnx->proto->num_connections > cnx->proto->max_connections) {
print_message(msg_connections_error, "%s: too many connections, dropping", cnx->proto->name);
return 1;
}
}
return 0;
}
void dec_proto_connections(struct connection* cnx)
{
if (cnx->proto) {
cnx->proto->num_connections--;
print_message(msg_connections, "Proto %s -1: %d/%d cnx\n",
cnx->proto->name,
cnx->proto->num_connections,
cnx->proto->max_connections);
}
}
/*
* moves data from one fd to other
*
@ -882,23 +849,16 @@ int check_access_rights(int in_socket, const char* service)
return 0;
}
volatile sig_atomic_t received_sigchld;
void sig_sigchld(int sig)
{
received_sigchld = 1;
}
void setup_signals(void)
{
int res;
struct sigaction action;
/* Set SIGCHLD to sig_sigchld() */
/* Request no SIGCHLD is sent upon termination of
* the children */
memset(&action, 0, sizeof(action));
action.sa_handler = sig_sigchld;
action.sa_flags = SA_NOCLDSTOP;
action.sa_handler = NULL;
action.sa_flags = SA_NOCLDWAIT;
res = sigaction(SIGCHLD, &action, NULL);
CHECK_RES_DIE(res, "sigaction");

View File

@ -109,7 +109,6 @@ struct connection {
struct sslhcfg_protocols_item* proto; /* Where to connect to */
/* SOCK_STREAM */
struct listen_endpoint* endpoint; /* Client-facing listen fd */
enum connection_state state;
time_t probe_timeout;
@ -139,8 +138,6 @@ struct listen_endpoint {
int socketfd; /* file descriptor of listening socket */
int type; /* SOCK_DGRAM | SOCK_STREAM */
int family; /* AF_INET | AF_UNIX */
int num_connections; /* How many active connections on this endpoint */
struct sslhcfg_listen_item* endpoint_cfg; /* the configuration item that corresponds to this endpoint */
};
#define FD_CNXCLOSED 0
@ -177,8 +174,6 @@ void drop_privileges(const char* user_name, const char* chroot_path);
void set_capabilities(int cap_net_admin);
void write_pid_file(const char* pidfile);
void dump_connection(struct connection *cnx);
int inc_proto_connections(struct connection* cnx);
void dec_proto_connections(struct connection* cnx);
int resolve_split_name(struct addrinfo **out, char* hostname, char* port);
int start_listen_sockets(struct listen_endpoint *sockfd[]);
@ -204,7 +199,4 @@ void main_loop(struct listen_endpoint *listen_sockets, int num_addr_listen);
void setup_landlock(void);
/* sslh-fork.c or processes.c, depending on the model */
void setup_sigchld(void);
#endif

View File

@ -200,12 +200,3 @@ process both single-datagram protocols such as DNS, and
connection-based protocols such as QUIC.
An example for supporting QUIC is shown in `example.cfg`.
Limiting file descriptor consumption
------------------------------------
There are various mechanisms to limit the number of
concurrent connections, which allows to limit the usage of
file descriptor. This is described in a separate
[guide](max_connections.md).

View File

@ -1,55 +0,0 @@
Limiting the number of connections
----------------------------------
As a network-facing service, `sslh` can be attacked by very
simple denial-of-service attacks by creating a lot of
concurrent connections. Protecting against such attacks is
complicated from the server side. This attack will cause
`sslh` to create a large number of file handles, which can
cause exgagerated resource consumption.
This threat can be mitigated using several limitation
mechanisms. Keep in mind that limiting the number of
connections means that in case of an attack, the server
resources are protected, but this might be at the expense of
serving legitimate connections. In particular, in some cases
this might mean SSH is no longer available.
There are several mechanisms to limit the number of
connections:
- Use `ulimit` (see bash(3) or your shell's man page) to
limit the number of file descriptors.
Then, `sslh` provides several mechanisms to limit the number
of concurrent connections, which in turns limits the number
of file descriptors used.
Essentially there are two ways to do this:
- you can set `max_connections` per protocol, and `sslh`
will drop connections after probing if the count is
exceeded. This should help in keeping SSH connections
available even if an attacker is stuffing other protocols.
Currently this does not work for forking protocols (support
is planned).
- you can set `max_connections` for each `listen` entry. So
the `sslh` process for each port will limit the number of
concurrent connections to that port. This is similar to the
`udp_max_connections` setting, but for TCP.
`sslh-select` and `sslh-ev` support both limit types.
`sslh-fork` has an explicit design goal to be as simple as
possible, which makes it impossible to implement limits per
protocol (because protocol probing is performed after the
process has forked). Limits will only work for `listen`
entries.
As of sslh 2.2.5, this is an experimental feature and not
all use cases have been tested. If 2.2.5 does not exist yet,
you must be on the Git's head, so it is even more
experimtental! Do not hesitate to send feedback if you
notice inconsistent behaviour.

View File

@ -1,120 +0,0 @@
Here is an example of deployment of sslh in transparent mode
using ansible and podman, [submitted by Github user
olegstepura](https://github.com/yrutschle/sslh/issues/448)
```yaml
# ansible podman task
- name: "Create sslh-co pod"
containers.podman.podman_pod:
name: sslh-co # read as "sslh and company"
state: started
ports:
- "80:80"
- "443:444"
# ... (more ports if needed)
network:
- '{{ containers.config.network }}' # other services from this network can access containers in this network for example prometheus can read caddy metrics at sslh-co:2020, also caddy itself can connect to other services to act as a reverse proxy
- name: "Create the sslh container"
containers.podman.podman_container:
name: sslh
image: "yrutschle/sslh:latest"
pod: sslh-co
capabilities:
- NET_RAW
- NET_BIND_SERVICE
- NET_ADMIN
sysctl:
net.ipv4.conf.default.route_localnet: 1
net.ipv4.conf.all.route_localnet: 1
expose:
- 444
volume:
# ... (make sure to mount config as you like)
command: --transparent -F/etc/sslh/sslh.cfg # parameter --transparent here is needed to trigger configure_iptables in init script
state: started
- name: "Create the caddy container"
containers.podman.podman_container:
name: caddy
image: "lucaslorentz/caddy-docker-proxy:alpine" # regular caddy or nginx image will also work
pod: sslh-co
expose:
- 80
- 443
- 2020 # metrics, since caddy-docker-proxy uses :2019 internally
volume:
# ... (mount your configs and other stuff here)
- "/var/run/podman/podman.sock:/var/run/docker.sock"
state: started
notify: podman restart sslh
- name: "Create the SSH proxy to host container"
containers.podman.podman_container:
name: ssh-proxy
image: "alpine/socat:latest"
pod: sslh-co
expose:
- 222
command: TCP-LISTEN:222,fork TCP:host.containers.internal:22
state: started
```
```ini
# sslh config
foreground: true;
inetd: false;
numeric: true;
transparent: true;
timeout: 5;
listen:
(
{ host: "0.0.0.0"; port: "444"; keepalive: true; },
);
protocols:
(
{
name: "ssh";
service: "ssh";
host: "localhost";
port: "222";
fork: true;
},
{
name: "http";
host: "localhost";
port: "80";
},
{
name: "tls";
host: "localhost";
port: "443";
},
);
```
I omitted caddy configs here as it's not important. Some unrelated container configs were also dropped.
In the example above `sslh`, `caddy` and `ssh-proxy` are 3 containers in the same pod, all listening on `localhost`. SSLH has to listen on `444` because caddy already listens on `443` and it's more complex to reconfigure caddy port because of let's encrypt (caddy itself "thinks" it is bound to your host interface).
Scheme of port mapping is (all containers share same `localhost`):
```
host 443 → pod 444 (sslh) → pod 443 (caddy)
```
- podman connects host `443` port to pod's `444` port
- `sslh` listens `444` on `localhost`, reroutes tls to `caddy` on `localhost:443`
- `caddy` listens `443` on `localhost` (reverse-proxies to other apps on private network)
Reverse-proxied services get correct IP in `X-Forwarded-For` header.
Takeaways:
- `net.ipv4.conf.default.route_localnet` is setup only in container, not on host, which is nice.
- same with iptables and route rules applied by `init` script in sslh container
- `sslh` proxy to other services in the private network will not work (because transparent mode is enabled) even if that other service does not need real IP
- with transparent mode all services that `sslh` will connect to should be attached to this pod making it listen on `localhost` of the pod
- ports of containers should not clash
- ports should be published on pod level, not on containers
- containers should not be configured to connect to custom networks
- because of the above proxying ssh to host will also not work out of the box, `sslh` should connect to `localhost` and not to a random IP. While adding another proxy as a container to the same pod sounds like an overkill I don't see any other solution, so `socat` is used as an additional proxy.
- `reverse_proxy` by caddy to other containers in the same custom network (as pod is attached to) works (e.g. caddy can connect to other IPs from custom network). `socat` can also connect to host and/or other containers in custom network.

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Wed Jul 16 17:59:23 2025.
* on Sun Apr 6 11:44:59 2025.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Wed Jul 16 17:59:23 2025.
* on Sun Apr 6 11:44:59 2025.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle

View File

@ -26,6 +26,7 @@
#include <pwd.h>
#include <syslog.h>
#include <libgen.h>
#include <getopt.h>
#include <errno.h>
#define cfg sslhcfg
@ -322,6 +323,9 @@ int start_listen_sockets(struct listen_endpoint *sockfd[])
int main(int argc, char *argv[])
{
extern char *optarg;
extern int optind;
int num_addr_listen;
struct listen_endpoint *listen_sockets;

View File

@ -49,15 +49,9 @@ syslog_facility: "auth";
# List of interfaces on which we should listen
# Options:
# host: name of the interface to listen to
# port: name of the service to listen to
# is_udp: listen in the UDP domain (default is TCP)
# is_unix: listen in the UNIX socket domain (default is TCP)
# keepalive: set TCP_KEEPALIVE
# max_connections: drop incoming connections after this count (sslh-fork only)
listen:
(
{ host: "thelonious"; port: "443"; max_connections: 5; },
{ host: "thelonious"; port: "443"; },
{ host: "thelonious"; port: "8080"; keepalive: true; },
{ host: "thelonious"; is_udp: true; port: "443"; },
{ host: "/tmp/unix_socket"; is_unix: true; port: ""; }
@ -76,11 +70,7 @@ listen:
# keepalive: Should TCP keepalive be on or off for that
# connection (default is off)
# fork: Should a new process be forked for this protocol?
# (only useful for sslh-select and sslh-ev)
# max_connections: further connections for this protocol
# will be rejected once the limit is reached. Does not
# work when fork is used (either in sslh-fork or if the
# previous option is set).
# (only useful for sslh-select)
# tfo_ok: Set to true if the server supports TCP FAST OPEN
# resolve_on_forward: Set to true if server address should be resolved on
# (every) newly incoming connection (again)

14
gap.c
View File

@ -59,11 +59,6 @@ gap_array* gap_init(int len)
return gap;
}
void gap_set_hardlimit(gap_array* gap, int index)
{
gap->hardlimit = index;
}
int gap_extend(gap_array* gap)
{
int elem_size = sizeof(gap->array[0]);
@ -93,11 +88,7 @@ void gap_destroy(gap_array* gap)
* is considered len elements long.
* A poor man's list, if you will. Currently only used to remove probing
* connections, so it only copies a few pointers at most.
* Returns:
* -1 if ptr was not found
* -2 if `len` is inconsistent with gap->len (i.e. trying to shift beyond the
* end of the array)
* */
* Returns -1 if ptr was not found */
int gap_remove_ptr(gap_array* gap, void* ptr, int len)
{
int start, i;
@ -111,9 +102,6 @@ int gap_remove_ptr(gap_array* gap, void* ptr, int len)
else
return -1;
if (gap->len < len)
return -2;
for (i = start; i < len - 1; i++) {
gap->array[i] = gap->array[i+1];
}

9
gap.h
View File

@ -4,7 +4,6 @@
typedef struct gap_array gap_array;
gap_array* gap_init(int len);
void gap_set_hardlimit(gap_array* ga, int index);
static void* gap_get(gap_array* gap, int index);
static int gap_set(gap_array* gap, int index, void* ptr);
void gap_destroy(gap_array* gap);
@ -14,8 +13,7 @@ int gap_remove_ptr(gap_array* gap, void* ptr, int len);
/* Private declarations to allow inlining.
* Don't assume my implementation. */
typedef struct gap_array {
int len; /* Number of elements in array (corresponds to the number of pages allocated) */
int hardlimit; /* Maximum index allowed after which sets will fail; 0 means no limit */
int len; /* Number of elements in array */
void** array;
} gap_array;
@ -23,9 +21,6 @@ int gap_extend(gap_array* gap);
static inline int __attribute__((unused)) gap_set(gap_array* gap, int index, void* ptr)
{
if (gap->hardlimit && (index > gap->hardlimit))
return -1;
while (index >= gap->len) {
int res = gap_extend(gap);
if (res == -1) return -1;
@ -42,8 +37,6 @@ static inline void* __attribute__((unused)) gap_get(gap_array* gap, int index)
* gap_get()'s job. This will do for now */
if (index >= gap->len) return NULL;
if (gap->hardlimit && (index > gap->hardlimit)) return NULL;
return gap->array[index];
}

63
probe.c
View File

@ -21,7 +21,10 @@
#define _GNU_SOURCE
#include <stdio.h>
#include <regex.h>
#ifdef ENABLE_REGEX
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
#endif
#include <ctype.h>
#include "probe.h"
#include "log.h"
@ -143,7 +146,6 @@ static int is_ssh_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_
#define OVPN_OPCODE_MASK 0xF8
#define OVPN_CONTROL_HARD_RESET_CLIENT_V1 (0x01 << 3)
#define OVPN_CONTROL_HARD_RESET_CLIENT_V2 (0x07 << 3)
#define OVPN_CONTROL_HARD_RESET_CLIENT_V3 (0x0A << 3)
#define OVPN_HMAC_128 16
#define OVPN_HMAC_160 20
#define OVPN_HARD_RESET_PACKET_ID_OFFSET(hmac_size) (9 + hmac_size)
@ -162,12 +164,8 @@ static int is_openvpn_protocol (const char*p,ssize_t len, struct sslhcfg_protoco
if (len < 1)
return PROBE_NEXT;
printf("opcode: %d\n", (p[0] & OVPN_OPCODE_MASK) >> 3);
if ((p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V1 &&
(p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V2 &&
(p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V3
)
(p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V2)
return PROBE_NEXT;
/* The detection pattern above may not be reliable enough.
@ -178,19 +176,13 @@ static int is_openvpn_protocol (const char*p,ssize_t len, struct sslhcfg_protoco
if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128) + sizeof(uint32_t))
return PROBE_NEXT;
uint32_t i;
/* OVPN_HMAC_128 is unaligned, which requires special care e.g. on ARM */
memcpy(&i, (p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128)), sizeof(i));
i = ntohl(i);
if (i <= 5u)
if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128))) <= 5u)
return PROBE_MATCH;
if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160) + sizeof(uint32_t))
return PROBE_NEXT;
memcpy(&i, (p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160)), sizeof(i));
i = ntohl(i);
if (i <= 5u)
if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160))) <= 5u)
return PROBE_MATCH;
return PROBE_NEXT;
@ -370,38 +362,17 @@ static int is_socks5_protocol(const char *p_in, ssize_t len, struct sslhcfg_prot
return PROBE_MATCH;
}
/* ******************
* is_syslog_protocol
* */
static regex_t syslog_preg;
static int configured_syslog_regex = 0;
static void config_syslog_regex(void)
{
/* two patterns for syslog messages:
* <12> My message
* 15 <12> My message
* 12 is 'priority', 1 to 3 digits (RFC4234)
* 15 is 'message length', a TCP-only option (RFC6587)
*/
int res = regcomp(&syslog_preg, "^([0-9]{1,3} )?<[0-9]{1,3}>", REG_EXTENDED);
if (res) {
print_message(msg_system_error, "regcomp");
exit(1);
}
configured_syslog_regex = 1;
}
static int is_syslog_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
{
char buf[len+1];
int res, i, j;
if (!configured_syslog_regex) config_syslog_regex();
res = sscanf(p, "<%d>", &i);
if (res == 1) return 1;
strncpy(buf, p, len);
buf[len] = 0;
res = sscanf(p, "%d <%d>", &i, &j);
if (res == 2) return 1;
return (regexec(&syslog_preg, buf, (size_t)0, NULL, 0) == 0);
return 0;
}
static int is_teamspeak_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
@ -425,18 +396,16 @@ static int is_msrdp_protocol(const char *p, ssize_t len, struct sslhcfg_protocol
return packet_len == len;
}
#ifdef ENABLE_REGEX
pcre2_match_data* probe_regex_matches;
#endif
static int regex_probe(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
{
#ifdef ENABLE_REGEX
pcre2_code**probe = (pcre2_code**)proto->data;
pcre2_match_data* matches;
matches = pcre2_match_data_create(1, NULL);
for (; *probe; probe++) {
int res = pcre2_match(*probe, (PCRE2_SPTR8)p, len, 0, 0, probe_regex_matches, NULL);
int res = pcre2_match(*probe, (PCRE2_SPTR8)p, len, 0, 0, matches, NULL);
if (res >= 0) return 1;
}

View File

@ -66,11 +66,4 @@ struct sslhcfg_protocols_item* timeout_protocol(void);
void hexdump(msg_info, const char*, unsigned int);
#ifdef ENABLE_REGEX
#define PCRE2_CODE_UNIT_WIDTH 8
#include <pcre2.h>
extern pcre2_match_data* probe_regex_matches;
#endif
#endif

View File

@ -49,9 +49,6 @@ int tidy_connection(struct connection *cnx, struct loop_info* fd_info)
if (gap_remove_ptr(fd_info->probing_list, cnx, fd_info->num_probing) != -1)
fd_info->num_probing--;
dec_proto_connections(cnx);
dec_listen_connections(cnx);
collection_remove_cnx(fd_info->collection, cnx);
return 0;
}
@ -93,7 +90,7 @@ struct connection* cnx_accept_process(struct loop_info* fd_info, struct listen_e
switch (type) {
case SOCK_STREAM:
cnx = accept_new_connection(listen_socket, fd_info);
cnx = accept_new_connection(fd, fd_info);
if (!cnx) return NULL;
break;

View File

@ -50,38 +50,22 @@ static int family_to_pp(int af_family)
typedef char libpp_addr[108]; /* This is hardcoded in libproxyprotocol/proxy_protocol.h */
typedef enum {
PEER,
SOCK
} sockpeer_t;
/* Fills *addr, *host and *serv with the connection information corresponding
* to fd. sockpeer indicates if if is filled with the remote, or local, part of
* the socket.
* *host is the IP address as string and *serv is the service (port)
* to fd. *host is the IP address as string and *serv is the service (port)
* */
static int get_info(int fd, sockpeer_t sockpeer, struct addrinfo* addr, libpp_addr* host, uint16_t* serv)
static int get_info(int fd, struct addrinfo* addr, libpp_addr* host, uint16_t* serv)
{
char serv_str[NI_MAXSERV];
int res;
if (sockpeer == PEER) {
res = getpeername(fd, addr->ai_addr, &addr->ai_addrlen);
CHECK_RES_RETURN(res, "getpeername", -1);
} else {
res = getsockname(fd, addr->ai_addr, &addr->ai_addrlen);
CHECK_RES_RETURN(res, "getsockname", -1);
}
res = getnameinfo(addr->ai_addr, addr->ai_addrlen,
(char*)host, sizeof(*host),
serv_str, sizeof(serv_str),
NI_NUMERICHOST | NI_NUMERICSERV );
if (res != 0) {
print_message(msg_system_error, "getnameinfo: %s\n", gai_strerror(res));
return -1;
}
CHECK_RES_RETURN(res, "getnameinfo", -1);
*serv = atoi(serv_str);
@ -105,14 +89,14 @@ int pp_write_header(int pp_version, struct connection* cnx)
addr.ai_addr = (struct sockaddr*)&ss;
addr.ai_addrlen = sizeof(ss);
res = get_info(cnx->q[0].fd, PEER,
res = get_info(cnx->q[0].fd,
&addr,
&pp_info_in_v1.src_addr,
&pp_info_in_v1.src_port);
if (res == -1) return -1;
pp_info_in_v1.address_family = family_to_pp(addr.ai_addr->sa_family);
res = get_info(cnx->q[1].fd, SOCK,
res = get_info(cnx->q[1].fd,
&addr,
&pp_info_in_v1.dst_addr,
&pp_info_in_v1.dst_port

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Mon Aug 4 18:25:44 2025.
* on Sun Apr 6 11:44:58 2025.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle
@ -712,22 +712,6 @@ static struct config_desc table_sslhcfg_protocols[] = {
/* default_val*/ .default_val.def_bool = 0
},
{
/* name */ "max_connections",
/* type */ CFG_INT,
/* sub_group*/ NULL,
/* arg_cl */ NULL,
/* base_addr */ NULL,
/* offset */ offsetof(struct sslhcfg_protocols_item, max_connections),
/* offset_len */ 0,
/* offset_present */ offsetof(struct sslhcfg_protocols_item, max_connections_is_present),
/* size */ sizeof(int),
/* array_type */ -1,
/* mandatory */ 0,
/* optional */ 1,
/* default_val*/ .default_val.def_int = 0
},
{
/* name */ "sni_hostnames",
/* type */ CFG_ARRAY,
@ -845,22 +829,6 @@ static struct config_desc table_sslhcfg_listen[] = {
/* default_val*/ .default_val.def_string = NULL
},
{
/* name */ "max_connections",
/* type */ CFG_INT,
/* sub_group*/ NULL,
/* arg_cl */ NULL,
/* base_addr */ NULL,
/* offset */ offsetof(struct sslhcfg_listen_item, max_connections),
/* offset_len */ 0,
/* offset_present */ offsetof(struct sslhcfg_listen_item, max_connections_is_present),
/* size */ sizeof(int),
/* array_type */ -1,
/* mandatory */ 0,
/* optional */ 1,
/* default_val*/ .default_val.def_int = 0
},
{
/* name */ "is_udp",
/* type */ CFG_BOOL,
@ -2453,11 +2421,6 @@ static void sslhcfg_protocols_fprint(
fprintf(out, "keepalive: %d", sslhcfg_protocols->keepalive);
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "max_connections: %d", sslhcfg_protocols->max_connections);
if (! sslhcfg_protocols->max_connections_is_present)
fprintf(out, " <unset>");
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "sni_hostnames [%zu]:\n", sslhcfg_protocols->sni_hostnames_len);
for (i = 0; i < sslhcfg_protocols->sni_hostnames_len; i++) {
indent(out, depth+1);
@ -2500,11 +2463,6 @@ static void sslhcfg_listen_fprint(
fprintf(out, "port: %s", sslhcfg_listen->port);
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "max_connections: %d", sslhcfg_listen->max_connections);
if (! sslhcfg_listen->max_connections_is_present)
fprintf(out, " <unset>");
fprintf(out, "\n");
indent(out, depth);
fprintf(out, "is_udp: %d", sslhcfg_listen->is_udp);
fprintf(out, "\n");
indent(out, depth);

View File

@ -1,5 +1,5 @@
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
* on Mon Aug 4 18:25:44 2025.
* on Sun Apr 6 11:44:58 2025.
# conf2struct: generate libconf parsers that read to structs
# Copyright (C) 2018-2024 Yves Rutschle
@ -43,8 +43,6 @@
struct sslhcfg_listen_item {
char* host;
char* port;
int max_connections_is_present;
int max_connections;
int is_udp;
int is_unix;
int keepalive;
@ -65,8 +63,6 @@ struct sslhcfg_protocols_item {
int resolve_on_forward;
int log_level;
int keepalive;
int max_connections_is_present;
int max_connections;
size_t sni_hostnames_len;
char** sni_hostnames;
size_t alpn_protocols_len;
@ -80,7 +76,6 @@ struct sslhcfg_protocols_item {
T_PROBE* probe;
struct addrinfo* saddr;
void* data;
unsigned int num_connections;
dl_list timeouts;
};

View File

@ -1,7 +1,7 @@
/*
sslh-fork: forking server
# Copyright (C) 2007-2025 Yves Rutschle
# Copyright (C) 2007-2021 Yves Rutschle
#
# This program is free software; you can redistribute it
# and/or modify it under the terms of the GNU General Public
@ -160,35 +160,6 @@ void set_listen_procname(struct listen_endpoint *listen_socket)
#endif
}
static void mask_sigchld(void)
{
struct sigaction action;
memset(&action, 0, sizeof(action));
action.sa_handler = NULL;
action.sa_flags = SA_NOCLDWAIT;
int res = sigaction(SIGCHLD, &action, NULL);
CHECK_RES_DIE(res, "sigaction");
}
extern volatile sig_atomic_t received_sigchld;
/* EINTR, so we probably received a signal; check if it's SIGCHLD */
static void process_signals(struct listen_endpoint* endpoint)
{
int chld;
if (received_sigchld) {
received_sigchld = 0;
do {
chld = waitpid(-1, NULL, WNOHANG);
CHECK_RES_RETURN(chld, "waitpid", );
if (chld) {
endpoint->num_connections--;
print_message(msg_fd, "child died, %d concurrent connections remaining\n", endpoint->num_connections);
}
} while (chld);
}
}
/* At least MacOS does not know these two options, so define them to something
* equivalent for our use case */
@ -213,7 +184,7 @@ void tcp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
if (in_socket == -1) {
print_message(msg_system_error, "%s:%d:%s:%d:%s\n",
__FILE__, __LINE__, "accept", errno, strerror(errno));
switch(errno) {
switch(in_socket) {
case ENETDOWN: /* accept(2) cites all these errnos as "you should retry" */
case EPROTO:
case ENOPROTOOPT:
@ -225,24 +196,11 @@ void tcp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
case ECONNABORTED:
continue;
case EINTR:
process_signals(endpoint);
continue;
default: /* Otherwise, it's something wrong in our parameters, we fail */
return;
}
}
endpoint->num_connections++;
print_message(msg_fd, "accepted fd %d (%d concurrent connections)\n", in_socket, endpoint->num_connections);
if ((endpoint->endpoint_cfg->max_connections_is_present)
&& (endpoint->num_connections > endpoint->endpoint_cfg->max_connections))
{
print_message(msg_fd, "too many connection, reclosing fd %d\n", in_socket);
endpoint->num_connections--;
close(in_socket);
continue;
}
print_message(msg_fd, "accepted fd %d\n", in_socket);
switch(fork()) {
case -1: print_message(msg_system_error, "fork failed: err %d: %s\n", errno, strerror(errno));
@ -292,10 +250,8 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
exit(0);
break;
/* We're in the parent, which does nothing but wait to be killed by
* SIGTERM, which it will send to its children */
/* We're in the parent, we don't need to do anything */
default:
mask_sigchld();
break;
}
}

View File

@ -130,7 +130,6 @@ static void setup_regex_probe(struct sslhcfg_protocols_item *p)
exit(1);
}
}
probe_regex_matches = pcre2_match_data_create(1, NULL);
}
#else
{
@ -281,6 +280,9 @@ void close_std(void)
int main(int argc, char *argv[], char* envp[])
{
extern char *optarg;
extern int optind;
int res, num_addr_listen;
struct listen_endpoint *listen_sockets;

View File

@ -156,15 +156,13 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
/* Check main socket for new connections */
for (i = 0; i < num_addr_listen; i++) {
if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) {
/* don't also process it as a read socket */
FD_CLR(listen_sockets[i].socketfd, &readfds);
struct connection* new_cnx = cnx_accept_process(&fd_info, &listen_sockets[i]);
struct connection* new_cnx;
while ((new_cnx = cnx_accept_process(&fd_info, &listen_sockets[i]))) {
if (fd_out_of_range(new_cnx->q[0].fd))
tidy_connection(new_cnx, &fd_info);
}
/* don't also process it as a read socket */
FD_CLR(listen_sockets[i].socketfd, &readfds);
}
}

View File

@ -97,7 +97,6 @@ config: {
items: (
{ name: "host"; type: "string"; var: true; },
{ name: "port"; type: "string"; var: true; },
{ name: "max_connections"; type: "int"; optional: true; },
{ name: "is_udp"; type: "bool"; default: false },
{ name: "is_unix"; type: "bool"; default: false },
{ name: "keepalive"; type: "bool"; default: false; }
@ -124,7 +123,6 @@ config: {
description: "Set to true if server address should be resolved on (every) newly incoming connection (again)" },
{ name: "log_level"; type: "int"; default: 1 },
{ name: "keepalive"; type: "bool"; default: false },
{ name: "max_connections"; type: "int"; optional: true },
{ name: "sni_hostnames",
type: "array",
element_type: "string"
@ -144,7 +142,6 @@ config: {
{ name: "probe"; type: "runtime"; c_type: "T_PROBE*" },
{ name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" },
{ name: "data"; type: "runtime"; c_type: "void*" },
{ name: "num_connections"; type: "runtime"; c_type: "unsigned int" },
{ name: "timeouts"; type: "runtime"; c_type: "dl_list" }
)
}

17
t
View File

@ -9,7 +9,7 @@
use strict;
use IO::Socket::INET6;
use Test::More qw/no_plan/;
use Conf::Libconfig 1.0.3;
use Conf::Libconfig;
my $conf = new Conf::Libconfig;
$conf->read_file("test.cfg");
@ -17,7 +17,7 @@ $conf->read_file("test.cfg");
my $no_listen = 8083; # Port on which no-one listens
my $pidfile = $conf->lookup_value("pidfile");
my $sslh_port = $conf->value("listen")->[0]->{port};
my $sslh_port = $conf->fetch_array("listen")->[0]->{port};
my $user = (getpwuid $<)[0]; # Run under current username
# Which tests do we run
@ -84,9 +84,8 @@ sub make_sni_alpn_name {
sub test_probe {
my (%opts) = @_;
print "test_probe [$opts{expected}] $sslh_port\n";
my $cnx = new IO::Socket::INET(PeerHost => "localhost:$sslh_port");
warn "t: $!\n" unless $cnx;
warn "$!\n" unless $cnx;
return unless $cnx;
my $pattern = $opts{data};
@ -120,7 +119,7 @@ sub test_probe {
sub test_probes {
my (%in_opts) = @_;
my @probes = @{$conf->value("protocols")};
my @probes = @{$conf->fetch_array("protocols")};
foreach my $p (@probes) {
my %protocols = (
'ssh' => { data => "SSH-2.0 tester" },
@ -195,7 +194,7 @@ sub test_probes {
# Start an echoserver for each service
foreach my $s (@{$conf->value("protocols")}) {
foreach my $s (@{$conf->fetch_array("protocols")}) {
my $prefix = $s->{name};
$prefix =~ s/^ssl/tls/; # To remove in 1.21
@ -218,7 +217,7 @@ for my $binary (@binaries) {
my ($sslh_pid, $valgrind);
if (!($sslh_pid = fork)) {
my $user = (getpwuid $<)[0]; # Run under current username
my $cmd = "./$binary -u $user -F test.cfg";
my $cmd = "./$binary -v 4 -f -u $user -F test.cfg";
#$valgrind = 1;
#$cmd = "valgrind --leak-check=full $cmd";
verbose_exec $cmd;
@ -340,11 +339,11 @@ if ($RB_CNX_NOSERVER) {
}
my $ssh_conf = (grep { $_->{name} eq "ssh" } @{$conf->value("protocols")})[0];
my $ssh_conf = (grep { $_->{name} eq "ssh" } @{$conf->fetch_array("protocols")})[0];
my $ssh_address = $ssh_conf->{host} . ":" . $ssh_conf->{port};
# Use the last TLS echoserv (no SNI/ALPN)
my $ssl_conf = (grep { $_->{name} eq "tls" } @{$conf->value ("protocols")})[-1];
my $ssl_conf = (grep { $_->{name} eq "tls" } @{$conf->fetch_array("protocols")})[-1];
my $ssl_address = $ssl_conf->{host} . ":" . $ssl_conf->{port};

View File

@ -118,45 +118,12 @@ void tcp_read_process(struct loop_info* fd_info,
}
}
/* *cnx must have its endpoint field filled;
* Increment the connection count for the listen endpoint.
* Return 1 if connection count is exceeded, 0 otherwise */
static int inc_listen_connections(struct connection* cnx)
{
cnx->endpoint->num_connections++;
if (cnx->endpoint->endpoint_cfg->max_connections_is_present) {
int num_cnx = cnx->endpoint->num_connections;
int max_cnx = cnx->endpoint->endpoint_cfg->max_connections;
print_message(msg_connections, "Endpoint %d +1: %d/%d cnx\n",
cnx->endpoint->socketfd, num_cnx, max_cnx);
if (num_cnx > max_cnx) {
print_message(msg_connections_error, "Endpoint %d: too many connections, dropping\n", cnx->endpoint->socketfd);
return 1;
}
}
return 0;
}
void dec_listen_connections(struct connection* cnx)
{
cnx->endpoint->num_connections--;
print_message(msg_connections, "Endpoint %d -1: %d/%d cnx\n",
cnx->endpoint->socketfd,
cnx->endpoint->num_connections,
cnx->endpoint->endpoint_cfg->max_connections);
}
/* Accepts a connection from the main socket and assigns it to an empty slot.
* If no slots are available, allocate another few. If that fails, drop the
* connexion */
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info)
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info)
{
int in_socket, res;
int listen_socket = endpoint->socketfd;
print_message(msg_fd, "accepting from %d\n", listen_socket);
@ -174,16 +141,12 @@ struct connection* accept_new_connection(struct listen_endpoint* endpoint, struc
close(in_socket);
return NULL;
}
cnx->endpoint = endpoint;
if (inc_listen_connections(cnx)) {
tidy_connection(cnx, fd_info);
return NULL;
}
add_probing_cnx(fd_info, cnx);
return cnx;
}
/* Connect queue 1 of connection to SSL; returns new file descriptor */
static int connect_queue(struct connection* cnx,
struct loop_info* fd_info)
@ -313,11 +276,6 @@ void probing_read_process(struct connection* cnx,
remove_probing_cnx(fd_info, cnx);
cnx->state = ST_SHOVELING;
if (inc_proto_connections(cnx)) {
tidy_connection(cnx, fd_info);
return;
}
/* libwrap check if required for this protocol */
if (cnx->proto->service &&
check_access_rights(cnx->q[0].fd, cnx->proto->service)) {

View File

@ -6,9 +6,8 @@
#include "tcp-probe.h"
void tcp_read_process(struct loop_info* fd_info, int fd);
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info);
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info);
void probing_read_process(struct connection* cnx, struct loop_info* fd_info);
void cnx_write_process(struct loop_info* fd_info, int fd);
void dec_listen_connections(struct connection* cnx);
#endif

View File

@ -19,7 +19,7 @@ verbose-config-error: 1; # print configuration errors
verbose-connections: 1; # trace established incoming address to forward address
verbose-connections-error: 1; # connection errors
verbose-connections-try: 1; # connection attempts towards targets
verbose-fd: 1; # file descriptor activity, open/close/whatnot
verbose-fd: 0; # file descriptor activity, open/close/whatnot
verbose-packets: 1; # hexdump packets on which probing is done
verbose-probe-info: 0; # what's happening during the probe process
verbose-probe-error: 1; # failures and problems during probing
@ -30,9 +30,9 @@ verbose-int-error: 1; # internal errors, the kind that should never happen
# Options:
listen:
(
{ host: "localhost"; port: "8080"; keepalive: true; max_connections: 2; },
{ host: "localhost"; port: "8080"; keepalive: true; },
{ host: "localhost"; port: "8081"; keepalive: true; },
# { host: "ip4-localhost"; is_udp: true; port: "8086"; },
{ host: "ip4-localhost"; is_udp: true; port: "8086"; },
{ host: "/tmp/sslh.sock"; is_unix: true; port: ""; }
);
@ -43,8 +43,7 @@ listen:
protocols:
(
{ name: "ssh"; host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true;
max_connections: 1; },
{ name: "ssh"; host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true; },
{ name: "socks5"; host: "localhost"; port: "9001"; },
{ name: "http"; host: "localhost"; port: "80"; proxyprotocol: 2; },
{ name: "tinc"; host: "localhost"; port: "9003"; },
@ -52,12 +51,11 @@ max_connections: 1; },
{ name: "xmpp"; host: "localhost"; port: "9009"; },
{ name: "adb"; host: "localhost"; port: "9010"; },
{ name: "syslog"; host: "localhost"; port: "9013"; },
# { name: "regex"; host: "ip4-localhost"; is_udp: true; port: "9020";
# max_connections: 1;
# udp_timeout: 30;
# regex_patterns: [ "^foo" ];
# resolve_on_forward: true;
# },
{ name: "regex"; host: "ip4-localhost"; is_udp: true; port: "9020";
udp_timeout: 30;
regex_patterns: [ "^foo" ];
resolve_on_forward: true;
},
{ name: "regex"; host: "localhost"; port: "9011";
regex_patterns: [ "^foo", "^bar" ];
minlength: 4;
@ -74,7 +72,6 @@ max_connections: 1; },
{ name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; },
{ name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; },
{ name: "tls"; host: "localhost"; port: "9025"; },
# { name: "anyprot"; host: "ip4-localhost"; is_udp: true; port: "9999"; },
{ name: "anyprot"; host: "localhost"; port: "9099"; }
);

View File

@ -1,7 +0,0 @@
CFLAGS=-DHASH_TESTING -O2 -Wall
OBJ=../gap.o gtest.o
gtest: $(OBJ)
$(CC) -o gtest $(OBJ)

View File

@ -1,102 +0,0 @@
/* Wee testing program from the gap code, this is very similar to the hash
* testing code.
* Instead of pointers, we use integers
*
* script language:
* a 5 12 # adds value 12 at index 5
* d 512 42 # remove value 42, 512 is the length of the array
* h 16 0 # set hard limit to 16 (value is not used)
*/
#include <stdlib.h>
#include <stddef.h>
#include <stdio.h>
#include <string.h>
#include "../gap.h"
static void gtest_next_line(FILE* f, char* action, int* index, void** value)
{
int res = 0;
while ((res != 3) && (res != EOF))
res = fscanf(f, "%c %d %p\n", action, index, value);
if (res == EOF) exit(0);
}
static void gap_dump(gap_array* gap, char* filename)
{
int i;
FILE* out = fopen(filename, "w");
if (!out) {
perror(filename);
exit(1);
}
fprintf(out, "<gap len=%d hardlimit=%d>\n", gap->len, gap->hardlimit);
for (i = 0; i < gap->len; i++) {
void* value = gap_get(gap, i);
fprintf(out, "[%d] = %p\n", i, value);
}
fprintf(out, "</gap>\n");
fclose(out);
}
int main(int argc, char* argv[])
{
gap_array* gap = gap_init(0);
char action;
int line = 0, index;
void* value;
FILE* f;
if (argc != 3) {
fprintf(stderr, "Usage: gtest <script file> <dump file>\n");
exit(1);
}
char* script_file = argv[1];
char* dump_file = argv[2];
f = fopen(argv[1], "r");
if (!f) {
perror(script_file);
exit(1);
}
while (1) {
action = ' ';
line++;
gtest_next_line(f, &action, &index, &value);
fprintf(stderr, "action %d: %c %d %p\n", line, action, index, value);
switch (action) {
case 'a': /* add */
fprintf(stderr, "[%d] = %p\n", index, value);
gap_set(gap, index, value);
break;
case 'd': /* del */
fprintf(stderr, "removing %p\n", value);
int res = gap_remove_ptr(gap, (void*)value, index);
fprintf(stderr, "remove: %d\n", res);
break;
case 'h': /* hardlimit */
fprintf(stderr, "setting hard limit %d\n", index);
gap_set_hardlimit(gap, index);
case 'g': /* get */
fprintf(stderr, "searching\n");
value = gap_get(gap, index);
fprintf(stderr, "got [%d]= %p\n", index, value);
break;
}
gap_dump(gap, dump_file);
}
return 0;
}

View File

@ -1,11 +0,0 @@
# Test hard limit
h 15 0 # set hard limit
a 5 42
a 6 43
a 15 44
a 16 45
a 17 46

View File

@ -1,514 +0,0 @@
<gap len=512 hardlimit=15>
[0] = (nil)
[1] = (nil)
[2] = (nil)
[3] = (nil)
[4] = (nil)
[5] = 0x42
[6] = 0x43
[7] = (nil)
[8] = (nil)
[9] = (nil)
[10] = (nil)
[11] = (nil)
[12] = (nil)
[13] = (nil)
[14] = (nil)
[15] = 0x44
[16] = (nil)
[17] = (nil)
[18] = (nil)
[19] = (nil)
[20] = (nil)
[21] = (nil)
[22] = (nil)
[23] = (nil)
[24] = (nil)
[25] = (nil)
[26] = (nil)
[27] = (nil)
[28] = (nil)
[29] = (nil)
[30] = (nil)
[31] = (nil)
[32] = (nil)
[33] = (nil)
[34] = (nil)
[35] = (nil)
[36] = (nil)
[37] = (nil)
[38] = (nil)
[39] = (nil)
[40] = (nil)
[41] = (nil)
[42] = (nil)
[43] = (nil)
[44] = (nil)
[45] = (nil)
[46] = (nil)
[47] = (nil)
[48] = (nil)
[49] = (nil)
[50] = (nil)
[51] = (nil)
[52] = (nil)
[53] = (nil)
[54] = (nil)
[55] = (nil)
[56] = (nil)
[57] = (nil)
[58] = (nil)
[59] = (nil)
[60] = (nil)
[61] = (nil)
[62] = (nil)
[63] = (nil)
[64] = (nil)
[65] = (nil)
[66] = (nil)
[67] = (nil)
[68] = (nil)
[69] = (nil)
[70] = (nil)
[71] = (nil)
[72] = (nil)
[73] = (nil)
[74] = (nil)
[75] = (nil)
[76] = (nil)
[77] = (nil)
[78] = (nil)
[79] = (nil)
[80] = (nil)
[81] = (nil)
[82] = (nil)
[83] = (nil)
[84] = (nil)
[85] = (nil)
[86] = (nil)
[87] = (nil)
[88] = (nil)
[89] = (nil)
[90] = (nil)
[91] = (nil)
[92] = (nil)
[93] = (nil)
[94] = (nil)
[95] = (nil)
[96] = (nil)
[97] = (nil)
[98] = (nil)
[99] = (nil)
[100] = (nil)
[101] = (nil)
[102] = (nil)
[103] = (nil)
[104] = (nil)
[105] = (nil)
[106] = (nil)
[107] = (nil)
[108] = (nil)
[109] = (nil)
[110] = (nil)
[111] = (nil)
[112] = (nil)
[113] = (nil)
[114] = (nil)
[115] = (nil)
[116] = (nil)
[117] = (nil)
[118] = (nil)
[119] = (nil)
[120] = (nil)
[121] = (nil)
[122] = (nil)
[123] = (nil)
[124] = (nil)
[125] = (nil)
[126] = (nil)
[127] = (nil)
[128] = (nil)
[129] = (nil)
[130] = (nil)
[131] = (nil)
[132] = (nil)
[133] = (nil)
[134] = (nil)
[135] = (nil)
[136] = (nil)
[137] = (nil)
[138] = (nil)
[139] = (nil)
[140] = (nil)
[141] = (nil)
[142] = (nil)
[143] = (nil)
[144] = (nil)
[145] = (nil)
[146] = (nil)
[147] = (nil)
[148] = (nil)
[149] = (nil)
[150] = (nil)
[151] = (nil)
[152] = (nil)
[153] = (nil)
[154] = (nil)
[155] = (nil)
[156] = (nil)
[157] = (nil)
[158] = (nil)
[159] = (nil)
[160] = (nil)
[161] = (nil)
[162] = (nil)
[163] = (nil)
[164] = (nil)
[165] = (nil)
[166] = (nil)
[167] = (nil)
[168] = (nil)
[169] = (nil)
[170] = (nil)
[171] = (nil)
[172] = (nil)
[173] = (nil)
[174] = (nil)
[175] = (nil)
[176] = (nil)
[177] = (nil)
[178] = (nil)
[179] = (nil)
[180] = (nil)
[181] = (nil)
[182] = (nil)
[183] = (nil)
[184] = (nil)
[185] = (nil)
[186] = (nil)
[187] = (nil)
[188] = (nil)
[189] = (nil)
[190] = (nil)
[191] = (nil)
[192] = (nil)
[193] = (nil)
[194] = (nil)
[195] = (nil)
[196] = (nil)
[197] = (nil)
[198] = (nil)
[199] = (nil)
[200] = (nil)
[201] = (nil)
[202] = (nil)
[203] = (nil)
[204] = (nil)
[205] = (nil)
[206] = (nil)
[207] = (nil)
[208] = (nil)
[209] = (nil)
[210] = (nil)
[211] = (nil)
[212] = (nil)
[213] = (nil)
[214] = (nil)
[215] = (nil)
[216] = (nil)
[217] = (nil)
[218] = (nil)
[219] = (nil)
[220] = (nil)
[221] = (nil)
[222] = (nil)
[223] = (nil)
[224] = (nil)
[225] = (nil)
[226] = (nil)
[227] = (nil)
[228] = (nil)
[229] = (nil)
[230] = (nil)
[231] = (nil)
[232] = (nil)
[233] = (nil)
[234] = (nil)
[235] = (nil)
[236] = (nil)
[237] = (nil)
[238] = (nil)
[239] = (nil)
[240] = (nil)
[241] = (nil)
[242] = (nil)
[243] = (nil)
[244] = (nil)
[245] = (nil)
[246] = (nil)
[247] = (nil)
[248] = (nil)
[249] = (nil)
[250] = (nil)
[251] = (nil)
[252] = (nil)
[253] = (nil)
[254] = (nil)
[255] = (nil)
[256] = (nil)
[257] = (nil)
[258] = (nil)
[259] = (nil)
[260] = (nil)
[261] = (nil)
[262] = (nil)
[263] = (nil)
[264] = (nil)
[265] = (nil)
[266] = (nil)
[267] = (nil)
[268] = (nil)
[269] = (nil)
[270] = (nil)
[271] = (nil)
[272] = (nil)
[273] = (nil)
[274] = (nil)
[275] = (nil)
[276] = (nil)
[277] = (nil)
[278] = (nil)
[279] = (nil)
[280] = (nil)
[281] = (nil)
[282] = (nil)
[283] = (nil)
[284] = (nil)
[285] = (nil)
[286] = (nil)
[287] = (nil)
[288] = (nil)
[289] = (nil)
[290] = (nil)
[291] = (nil)
[292] = (nil)
[293] = (nil)
[294] = (nil)
[295] = (nil)
[296] = (nil)
[297] = (nil)
[298] = (nil)
[299] = (nil)
[300] = (nil)
[301] = (nil)
[302] = (nil)
[303] = (nil)
[304] = (nil)
[305] = (nil)
[306] = (nil)
[307] = (nil)
[308] = (nil)
[309] = (nil)
[310] = (nil)
[311] = (nil)
[312] = (nil)
[313] = (nil)
[314] = (nil)
[315] = (nil)
[316] = (nil)
[317] = (nil)
[318] = (nil)
[319] = (nil)
[320] = (nil)
[321] = (nil)
[322] = (nil)
[323] = (nil)
[324] = (nil)
[325] = (nil)
[326] = (nil)
[327] = (nil)
[328] = (nil)
[329] = (nil)
[330] = (nil)
[331] = (nil)
[332] = (nil)
[333] = (nil)
[334] = (nil)
[335] = (nil)
[336] = (nil)
[337] = (nil)
[338] = (nil)
[339] = (nil)
[340] = (nil)
[341] = (nil)
[342] = (nil)
[343] = (nil)
[344] = (nil)
[345] = (nil)
[346] = (nil)
[347] = (nil)
[348] = (nil)
[349] = (nil)
[350] = (nil)
[351] = (nil)
[352] = (nil)
[353] = (nil)
[354] = (nil)
[355] = (nil)
[356] = (nil)
[357] = (nil)
[358] = (nil)
[359] = (nil)
[360] = (nil)
[361] = (nil)
[362] = (nil)
[363] = (nil)
[364] = (nil)
[365] = (nil)
[366] = (nil)
[367] = (nil)
[368] = (nil)
[369] = (nil)
[370] = (nil)
[371] = (nil)
[372] = (nil)
[373] = (nil)
[374] = (nil)
[375] = (nil)
[376] = (nil)
[377] = (nil)
[378] = (nil)
[379] = (nil)
[380] = (nil)
[381] = (nil)
[382] = (nil)
[383] = (nil)
[384] = (nil)
[385] = (nil)
[386] = (nil)
[387] = (nil)
[388] = (nil)
[389] = (nil)
[390] = (nil)
[391] = (nil)
[392] = (nil)
[393] = (nil)
[394] = (nil)
[395] = (nil)
[396] = (nil)
[397] = (nil)
[398] = (nil)
[399] = (nil)
[400] = (nil)
[401] = (nil)
[402] = (nil)
[403] = (nil)
[404] = (nil)
[405] = (nil)
[406] = (nil)
[407] = (nil)
[408] = (nil)
[409] = (nil)
[410] = (nil)
[411] = (nil)
[412] = (nil)
[413] = (nil)
[414] = (nil)
[415] = (nil)
[416] = (nil)
[417] = (nil)
[418] = (nil)
[419] = (nil)
[420] = (nil)
[421] = (nil)
[422] = (nil)
[423] = (nil)
[424] = (nil)
[425] = (nil)
[426] = (nil)
[427] = (nil)
[428] = (nil)
[429] = (nil)
[430] = (nil)
[431] = (nil)
[432] = (nil)
[433] = (nil)
[434] = (nil)
[435] = (nil)
[436] = (nil)
[437] = (nil)
[438] = (nil)
[439] = (nil)
[440] = (nil)
[441] = (nil)
[442] = (nil)
[443] = (nil)
[444] = (nil)
[445] = (nil)
[446] = (nil)
[447] = (nil)
[448] = (nil)
[449] = (nil)
[450] = (nil)
[451] = (nil)
[452] = (nil)
[453] = (nil)
[454] = (nil)
[455] = (nil)
[456] = (nil)
[457] = (nil)
[458] = (nil)
[459] = (nil)
[460] = (nil)
[461] = (nil)
[462] = (nil)
[463] = (nil)
[464] = (nil)
[465] = (nil)
[466] = (nil)
[467] = (nil)
[468] = (nil)
[469] = (nil)
[470] = (nil)
[471] = (nil)
[472] = (nil)
[473] = (nil)
[474] = (nil)
[475] = (nil)
[476] = (nil)
[477] = (nil)
[478] = (nil)
[479] = (nil)
[480] = (nil)
[481] = (nil)
[482] = (nil)
[483] = (nil)
[484] = (nil)
[485] = (nil)
[486] = (nil)
[487] = (nil)
[488] = (nil)
[489] = (nil)
[490] = (nil)
[491] = (nil)
[492] = (nil)
[493] = (nil)
[494] = (nil)
[495] = (nil)
[496] = (nil)
[497] = (nil)
[498] = (nil)
[499] = (nil)
[500] = (nil)
[501] = (nil)
[502] = (nil)
[503] = (nil)
[504] = (nil)
[505] = (nil)
[506] = (nil)
[507] = (nil)
[508] = (nil)
[509] = (nil)
[510] = (nil)
[511] = (nil)
</gap>

View File

@ -1,5 +0,0 @@
# Insertions after the first page, to extend the gap
a 5 42
a 1024 43
a 1028 44

File diff suppressed because it is too large Load Diff

View File

@ -1,6 +0,0 @@
# Simple insertions in the first page
a 5 42
a 10 43

View File

@ -1,514 +0,0 @@
<gap len=512 hardlimit=0>
[0] = (nil)
[1] = (nil)
[2] = (nil)
[3] = (nil)
[4] = (nil)
[5] = 0x42
[6] = (nil)
[7] = (nil)
[8] = (nil)
[9] = (nil)
[10] = 0x43
[11] = (nil)
[12] = (nil)
[13] = (nil)
[14] = (nil)
[15] = (nil)
[16] = (nil)
[17] = (nil)
[18] = (nil)
[19] = (nil)
[20] = (nil)
[21] = (nil)
[22] = (nil)
[23] = (nil)
[24] = (nil)
[25] = (nil)
[26] = (nil)
[27] = (nil)
[28] = (nil)
[29] = (nil)
[30] = (nil)
[31] = (nil)
[32] = (nil)
[33] = (nil)
[34] = (nil)
[35] = (nil)
[36] = (nil)
[37] = (nil)
[38] = (nil)
[39] = (nil)
[40] = (nil)
[41] = (nil)
[42] = (nil)
[43] = (nil)
[44] = (nil)
[45] = (nil)
[46] = (nil)
[47] = (nil)
[48] = (nil)
[49] = (nil)
[50] = (nil)
[51] = (nil)
[52] = (nil)
[53] = (nil)
[54] = (nil)
[55] = (nil)
[56] = (nil)
[57] = (nil)
[58] = (nil)
[59] = (nil)
[60] = (nil)
[61] = (nil)
[62] = (nil)
[63] = (nil)
[64] = (nil)
[65] = (nil)
[66] = (nil)
[67] = (nil)
[68] = (nil)
[69] = (nil)
[70] = (nil)
[71] = (nil)
[72] = (nil)
[73] = (nil)
[74] = (nil)
[75] = (nil)
[76] = (nil)
[77] = (nil)
[78] = (nil)
[79] = (nil)
[80] = (nil)
[81] = (nil)
[82] = (nil)
[83] = (nil)
[84] = (nil)
[85] = (nil)
[86] = (nil)
[87] = (nil)
[88] = (nil)
[89] = (nil)
[90] = (nil)
[91] = (nil)
[92] = (nil)
[93] = (nil)
[94] = (nil)
[95] = (nil)
[96] = (nil)
[97] = (nil)
[98] = (nil)
[99] = (nil)
[100] = (nil)
[101] = (nil)
[102] = (nil)
[103] = (nil)
[104] = (nil)
[105] = (nil)
[106] = (nil)
[107] = (nil)
[108] = (nil)
[109] = (nil)
[110] = (nil)
[111] = (nil)
[112] = (nil)
[113] = (nil)
[114] = (nil)
[115] = (nil)
[116] = (nil)
[117] = (nil)
[118] = (nil)
[119] = (nil)
[120] = (nil)
[121] = (nil)
[122] = (nil)
[123] = (nil)
[124] = (nil)
[125] = (nil)
[126] = (nil)
[127] = (nil)
[128] = (nil)
[129] = (nil)
[130] = (nil)
[131] = (nil)
[132] = (nil)
[133] = (nil)
[134] = (nil)
[135] = (nil)
[136] = (nil)
[137] = (nil)
[138] = (nil)
[139] = (nil)
[140] = (nil)
[141] = (nil)
[142] = (nil)
[143] = (nil)
[144] = (nil)
[145] = (nil)
[146] = (nil)
[147] = (nil)
[148] = (nil)
[149] = (nil)
[150] = (nil)
[151] = (nil)
[152] = (nil)
[153] = (nil)
[154] = (nil)
[155] = (nil)
[156] = (nil)
[157] = (nil)
[158] = (nil)
[159] = (nil)
[160] = (nil)
[161] = (nil)
[162] = (nil)
[163] = (nil)
[164] = (nil)
[165] = (nil)
[166] = (nil)
[167] = (nil)
[168] = (nil)
[169] = (nil)
[170] = (nil)
[171] = (nil)
[172] = (nil)
[173] = (nil)
[174] = (nil)
[175] = (nil)
[176] = (nil)
[177] = (nil)
[178] = (nil)
[179] = (nil)
[180] = (nil)
[181] = (nil)
[182] = (nil)
[183] = (nil)
[184] = (nil)
[185] = (nil)
[186] = (nil)
[187] = (nil)
[188] = (nil)
[189] = (nil)
[190] = (nil)
[191] = (nil)
[192] = (nil)
[193] = (nil)
[194] = (nil)
[195] = (nil)
[196] = (nil)
[197] = (nil)
[198] = (nil)
[199] = (nil)
[200] = (nil)
[201] = (nil)
[202] = (nil)
[203] = (nil)
[204] = (nil)
[205] = (nil)
[206] = (nil)
[207] = (nil)
[208] = (nil)
[209] = (nil)
[210] = (nil)
[211] = (nil)
[212] = (nil)
[213] = (nil)
[214] = (nil)
[215] = (nil)
[216] = (nil)
[217] = (nil)
[218] = (nil)
[219] = (nil)
[220] = (nil)
[221] = (nil)
[222] = (nil)
[223] = (nil)
[224] = (nil)
[225] = (nil)
[226] = (nil)
[227] = (nil)
[228] = (nil)
[229] = (nil)
[230] = (nil)
[231] = (nil)
[232] = (nil)
[233] = (nil)
[234] = (nil)
[235] = (nil)
[236] = (nil)
[237] = (nil)
[238] = (nil)
[239] = (nil)
[240] = (nil)
[241] = (nil)
[242] = (nil)
[243] = (nil)
[244] = (nil)
[245] = (nil)
[246] = (nil)
[247] = (nil)
[248] = (nil)
[249] = (nil)
[250] = (nil)
[251] = (nil)
[252] = (nil)
[253] = (nil)
[254] = (nil)
[255] = (nil)
[256] = (nil)
[257] = (nil)
[258] = (nil)
[259] = (nil)
[260] = (nil)
[261] = (nil)
[262] = (nil)
[263] = (nil)
[264] = (nil)
[265] = (nil)
[266] = (nil)
[267] = (nil)
[268] = (nil)
[269] = (nil)
[270] = (nil)
[271] = (nil)
[272] = (nil)
[273] = (nil)
[274] = (nil)
[275] = (nil)
[276] = (nil)
[277] = (nil)
[278] = (nil)
[279] = (nil)
[280] = (nil)
[281] = (nil)
[282] = (nil)
[283] = (nil)
[284] = (nil)
[285] = (nil)
[286] = (nil)
[287] = (nil)
[288] = (nil)
[289] = (nil)
[290] = (nil)
[291] = (nil)
[292] = (nil)
[293] = (nil)
[294] = (nil)
[295] = (nil)
[296] = (nil)
[297] = (nil)
[298] = (nil)
[299] = (nil)
[300] = (nil)
[301] = (nil)
[302] = (nil)
[303] = (nil)
[304] = (nil)
[305] = (nil)
[306] = (nil)
[307] = (nil)
[308] = (nil)
[309] = (nil)
[310] = (nil)
[311] = (nil)
[312] = (nil)
[313] = (nil)
[314] = (nil)
[315] = (nil)
[316] = (nil)
[317] = (nil)
[318] = (nil)
[319] = (nil)
[320] = (nil)
[321] = (nil)
[322] = (nil)
[323] = (nil)
[324] = (nil)
[325] = (nil)
[326] = (nil)
[327] = (nil)
[328] = (nil)
[329] = (nil)
[330] = (nil)
[331] = (nil)
[332] = (nil)
[333] = (nil)
[334] = (nil)
[335] = (nil)
[336] = (nil)
[337] = (nil)
[338] = (nil)
[339] = (nil)
[340] = (nil)
[341] = (nil)
[342] = (nil)
[343] = (nil)
[344] = (nil)
[345] = (nil)
[346] = (nil)
[347] = (nil)
[348] = (nil)
[349] = (nil)
[350] = (nil)
[351] = (nil)
[352] = (nil)
[353] = (nil)
[354] = (nil)
[355] = (nil)
[356] = (nil)
[357] = (nil)
[358] = (nil)
[359] = (nil)
[360] = (nil)
[361] = (nil)
[362] = (nil)
[363] = (nil)
[364] = (nil)
[365] = (nil)
[366] = (nil)
[367] = (nil)
[368] = (nil)
[369] = (nil)
[370] = (nil)
[371] = (nil)
[372] = (nil)
[373] = (nil)
[374] = (nil)
[375] = (nil)
[376] = (nil)
[377] = (nil)
[378] = (nil)
[379] = (nil)
[380] = (nil)
[381] = (nil)
[382] = (nil)
[383] = (nil)
[384] = (nil)
[385] = (nil)
[386] = (nil)
[387] = (nil)
[388] = (nil)
[389] = (nil)
[390] = (nil)
[391] = (nil)
[392] = (nil)
[393] = (nil)
[394] = (nil)
[395] = (nil)
[396] = (nil)
[397] = (nil)
[398] = (nil)
[399] = (nil)
[400] = (nil)
[401] = (nil)
[402] = (nil)
[403] = (nil)
[404] = (nil)
[405] = (nil)
[406] = (nil)
[407] = (nil)
[408] = (nil)
[409] = (nil)
[410] = (nil)
[411] = (nil)
[412] = (nil)
[413] = (nil)
[414] = (nil)
[415] = (nil)
[416] = (nil)
[417] = (nil)
[418] = (nil)
[419] = (nil)
[420] = (nil)
[421] = (nil)
[422] = (nil)
[423] = (nil)
[424] = (nil)
[425] = (nil)
[426] = (nil)
[427] = (nil)
[428] = (nil)
[429] = (nil)
[430] = (nil)
[431] = (nil)
[432] = (nil)
[433] = (nil)
[434] = (nil)
[435] = (nil)
[436] = (nil)
[437] = (nil)
[438] = (nil)
[439] = (nil)
[440] = (nil)
[441] = (nil)
[442] = (nil)
[443] = (nil)
[444] = (nil)
[445] = (nil)
[446] = (nil)
[447] = (nil)
[448] = (nil)
[449] = (nil)
[450] = (nil)
[451] = (nil)
[452] = (nil)
[453] = (nil)
[454] = (nil)
[455] = (nil)
[456] = (nil)
[457] = (nil)
[458] = (nil)
[459] = (nil)
[460] = (nil)
[461] = (nil)
[462] = (nil)
[463] = (nil)
[464] = (nil)
[465] = (nil)
[466] = (nil)
[467] = (nil)
[468] = (nil)
[469] = (nil)
[470] = (nil)
[471] = (nil)
[472] = (nil)
[473] = (nil)
[474] = (nil)
[475] = (nil)
[476] = (nil)
[477] = (nil)
[478] = (nil)
[479] = (nil)
[480] = (nil)
[481] = (nil)
[482] = (nil)
[483] = (nil)
[484] = (nil)
[485] = (nil)
[486] = (nil)
[487] = (nil)
[488] = (nil)
[489] = (nil)
[490] = (nil)
[491] = (nil)
[492] = (nil)
[493] = (nil)
[494] = (nil)
[495] = (nil)
[496] = (nil)
[497] = (nil)
[498] = (nil)
[499] = (nil)
[500] = (nil)
[501] = (nil)
[502] = (nil)
[503] = (nil)
[504] = (nil)
[505] = (nil)
[506] = (nil)
[507] = (nil)
[508] = (nil)
[509] = (nil)
[510] = (nil)
[511] = (nil)
</gap>

View File

@ -1,10 +0,0 @@
# Remove values
a 5 42
a 10 43
a 13 44
a 510 45
a 511 46
d 512 43

View File

@ -1,514 +0,0 @@
<gap len=512 hardlimit=0>
[0] = (nil)
[1] = (nil)
[2] = (nil)
[3] = (nil)
[4] = (nil)
[5] = 0x42
[6] = (nil)
[7] = (nil)
[8] = (nil)
[9] = (nil)
[10] = (nil)
[11] = (nil)
[12] = 0x44
[13] = (nil)
[14] = (nil)
[15] = (nil)
[16] = (nil)
[17] = (nil)
[18] = (nil)
[19] = (nil)
[20] = (nil)
[21] = (nil)
[22] = (nil)
[23] = (nil)
[24] = (nil)
[25] = (nil)
[26] = (nil)
[27] = (nil)
[28] = (nil)
[29] = (nil)
[30] = (nil)
[31] = (nil)
[32] = (nil)
[33] = (nil)
[34] = (nil)
[35] = (nil)
[36] = (nil)
[37] = (nil)
[38] = (nil)
[39] = (nil)
[40] = (nil)
[41] = (nil)
[42] = (nil)
[43] = (nil)
[44] = (nil)
[45] = (nil)
[46] = (nil)
[47] = (nil)
[48] = (nil)
[49] = (nil)
[50] = (nil)
[51] = (nil)
[52] = (nil)
[53] = (nil)
[54] = (nil)
[55] = (nil)
[56] = (nil)
[57] = (nil)
[58] = (nil)
[59] = (nil)
[60] = (nil)
[61] = (nil)
[62] = (nil)
[63] = (nil)
[64] = (nil)
[65] = (nil)
[66] = (nil)
[67] = (nil)
[68] = (nil)
[69] = (nil)
[70] = (nil)
[71] = (nil)
[72] = (nil)
[73] = (nil)
[74] = (nil)
[75] = (nil)
[76] = (nil)
[77] = (nil)
[78] = (nil)
[79] = (nil)
[80] = (nil)
[81] = (nil)
[82] = (nil)
[83] = (nil)
[84] = (nil)
[85] = (nil)
[86] = (nil)
[87] = (nil)
[88] = (nil)
[89] = (nil)
[90] = (nil)
[91] = (nil)
[92] = (nil)
[93] = (nil)
[94] = (nil)
[95] = (nil)
[96] = (nil)
[97] = (nil)
[98] = (nil)
[99] = (nil)
[100] = (nil)
[101] = (nil)
[102] = (nil)
[103] = (nil)
[104] = (nil)
[105] = (nil)
[106] = (nil)
[107] = (nil)
[108] = (nil)
[109] = (nil)
[110] = (nil)
[111] = (nil)
[112] = (nil)
[113] = (nil)
[114] = (nil)
[115] = (nil)
[116] = (nil)
[117] = (nil)
[118] = (nil)
[119] = (nil)
[120] = (nil)
[121] = (nil)
[122] = (nil)
[123] = (nil)
[124] = (nil)
[125] = (nil)
[126] = (nil)
[127] = (nil)
[128] = (nil)
[129] = (nil)
[130] = (nil)
[131] = (nil)
[132] = (nil)
[133] = (nil)
[134] = (nil)
[135] = (nil)
[136] = (nil)
[137] = (nil)
[138] = (nil)
[139] = (nil)
[140] = (nil)
[141] = (nil)
[142] = (nil)
[143] = (nil)
[144] = (nil)
[145] = (nil)
[146] = (nil)
[147] = (nil)
[148] = (nil)
[149] = (nil)
[150] = (nil)
[151] = (nil)
[152] = (nil)
[153] = (nil)
[154] = (nil)
[155] = (nil)
[156] = (nil)
[157] = (nil)
[158] = (nil)
[159] = (nil)
[160] = (nil)
[161] = (nil)
[162] = (nil)
[163] = (nil)
[164] = (nil)
[165] = (nil)
[166] = (nil)
[167] = (nil)
[168] = (nil)
[169] = (nil)
[170] = (nil)
[171] = (nil)
[172] = (nil)
[173] = (nil)
[174] = (nil)
[175] = (nil)
[176] = (nil)
[177] = (nil)
[178] = (nil)
[179] = (nil)
[180] = (nil)
[181] = (nil)
[182] = (nil)
[183] = (nil)
[184] = (nil)
[185] = (nil)
[186] = (nil)
[187] = (nil)
[188] = (nil)
[189] = (nil)
[190] = (nil)
[191] = (nil)
[192] = (nil)
[193] = (nil)
[194] = (nil)
[195] = (nil)
[196] = (nil)
[197] = (nil)
[198] = (nil)
[199] = (nil)
[200] = (nil)
[201] = (nil)
[202] = (nil)
[203] = (nil)
[204] = (nil)
[205] = (nil)
[206] = (nil)
[207] = (nil)
[208] = (nil)
[209] = (nil)
[210] = (nil)
[211] = (nil)
[212] = (nil)
[213] = (nil)
[214] = (nil)
[215] = (nil)
[216] = (nil)
[217] = (nil)
[218] = (nil)
[219] = (nil)
[220] = (nil)
[221] = (nil)
[222] = (nil)
[223] = (nil)
[224] = (nil)
[225] = (nil)
[226] = (nil)
[227] = (nil)
[228] = (nil)
[229] = (nil)
[230] = (nil)
[231] = (nil)
[232] = (nil)
[233] = (nil)
[234] = (nil)
[235] = (nil)
[236] = (nil)
[237] = (nil)
[238] = (nil)
[239] = (nil)
[240] = (nil)
[241] = (nil)
[242] = (nil)
[243] = (nil)
[244] = (nil)
[245] = (nil)
[246] = (nil)
[247] = (nil)
[248] = (nil)
[249] = (nil)
[250] = (nil)
[251] = (nil)
[252] = (nil)
[253] = (nil)
[254] = (nil)
[255] = (nil)
[256] = (nil)
[257] = (nil)
[258] = (nil)
[259] = (nil)
[260] = (nil)
[261] = (nil)
[262] = (nil)
[263] = (nil)
[264] = (nil)
[265] = (nil)
[266] = (nil)
[267] = (nil)
[268] = (nil)
[269] = (nil)
[270] = (nil)
[271] = (nil)
[272] = (nil)
[273] = (nil)
[274] = (nil)
[275] = (nil)
[276] = (nil)
[277] = (nil)
[278] = (nil)
[279] = (nil)
[280] = (nil)
[281] = (nil)
[282] = (nil)
[283] = (nil)
[284] = (nil)
[285] = (nil)
[286] = (nil)
[287] = (nil)
[288] = (nil)
[289] = (nil)
[290] = (nil)
[291] = (nil)
[292] = (nil)
[293] = (nil)
[294] = (nil)
[295] = (nil)
[296] = (nil)
[297] = (nil)
[298] = (nil)
[299] = (nil)
[300] = (nil)
[301] = (nil)
[302] = (nil)
[303] = (nil)
[304] = (nil)
[305] = (nil)
[306] = (nil)
[307] = (nil)
[308] = (nil)
[309] = (nil)
[310] = (nil)
[311] = (nil)
[312] = (nil)
[313] = (nil)
[314] = (nil)
[315] = (nil)
[316] = (nil)
[317] = (nil)
[318] = (nil)
[319] = (nil)
[320] = (nil)
[321] = (nil)
[322] = (nil)
[323] = (nil)
[324] = (nil)
[325] = (nil)
[326] = (nil)
[327] = (nil)
[328] = (nil)
[329] = (nil)
[330] = (nil)
[331] = (nil)
[332] = (nil)
[333] = (nil)
[334] = (nil)
[335] = (nil)
[336] = (nil)
[337] = (nil)
[338] = (nil)
[339] = (nil)
[340] = (nil)
[341] = (nil)
[342] = (nil)
[343] = (nil)
[344] = (nil)
[345] = (nil)
[346] = (nil)
[347] = (nil)
[348] = (nil)
[349] = (nil)
[350] = (nil)
[351] = (nil)
[352] = (nil)
[353] = (nil)
[354] = (nil)
[355] = (nil)
[356] = (nil)
[357] = (nil)
[358] = (nil)
[359] = (nil)
[360] = (nil)
[361] = (nil)
[362] = (nil)
[363] = (nil)
[364] = (nil)
[365] = (nil)
[366] = (nil)
[367] = (nil)
[368] = (nil)
[369] = (nil)
[370] = (nil)
[371] = (nil)
[372] = (nil)
[373] = (nil)
[374] = (nil)
[375] = (nil)
[376] = (nil)
[377] = (nil)
[378] = (nil)
[379] = (nil)
[380] = (nil)
[381] = (nil)
[382] = (nil)
[383] = (nil)
[384] = (nil)
[385] = (nil)
[386] = (nil)
[387] = (nil)
[388] = (nil)
[389] = (nil)
[390] = (nil)
[391] = (nil)
[392] = (nil)
[393] = (nil)
[394] = (nil)
[395] = (nil)
[396] = (nil)
[397] = (nil)
[398] = (nil)
[399] = (nil)
[400] = (nil)
[401] = (nil)
[402] = (nil)
[403] = (nil)
[404] = (nil)
[405] = (nil)
[406] = (nil)
[407] = (nil)
[408] = (nil)
[409] = (nil)
[410] = (nil)
[411] = (nil)
[412] = (nil)
[413] = (nil)
[414] = (nil)
[415] = (nil)
[416] = (nil)
[417] = (nil)
[418] = (nil)
[419] = (nil)
[420] = (nil)
[421] = (nil)
[422] = (nil)
[423] = (nil)
[424] = (nil)
[425] = (nil)
[426] = (nil)
[427] = (nil)
[428] = (nil)
[429] = (nil)
[430] = (nil)
[431] = (nil)
[432] = (nil)
[433] = (nil)
[434] = (nil)
[435] = (nil)
[436] = (nil)
[437] = (nil)
[438] = (nil)
[439] = (nil)
[440] = (nil)
[441] = (nil)
[442] = (nil)
[443] = (nil)
[444] = (nil)
[445] = (nil)
[446] = (nil)
[447] = (nil)
[448] = (nil)
[449] = (nil)
[450] = (nil)
[451] = (nil)
[452] = (nil)
[453] = (nil)
[454] = (nil)
[455] = (nil)
[456] = (nil)
[457] = (nil)
[458] = (nil)
[459] = (nil)
[460] = (nil)
[461] = (nil)
[462] = (nil)
[463] = (nil)
[464] = (nil)
[465] = (nil)
[466] = (nil)
[467] = (nil)
[468] = (nil)
[469] = (nil)
[470] = (nil)
[471] = (nil)
[472] = (nil)
[473] = (nil)
[474] = (nil)
[475] = (nil)
[476] = (nil)
[477] = (nil)
[478] = (nil)
[479] = (nil)
[480] = (nil)
[481] = (nil)
[482] = (nil)
[483] = (nil)
[484] = (nil)
[485] = (nil)
[486] = (nil)
[487] = (nil)
[488] = (nil)
[489] = (nil)
[490] = (nil)
[491] = (nil)
[492] = (nil)
[493] = (nil)
[494] = (nil)
[495] = (nil)
[496] = (nil)
[497] = (nil)
[498] = (nil)
[499] = (nil)
[500] = (nil)
[501] = (nil)
[502] = (nil)
[503] = (nil)
[504] = (nil)
[505] = (nil)
[506] = (nil)
[507] = (nil)
[508] = (nil)
[509] = 0x45
[510] = 0x46
[511] = 0x46
</gap>

View File

@ -1,30 +0,0 @@
#! /usr/bin/perl -w
# This runs all the tests.
# Tests scripts are in *.tst files.
# Corresponding output is put in *.out.
# Reference output is put in *.ref.
# Any discrepancy will be reported!
use strict;
my @res;
foreach my $fn (`ls *.tst`) {
chomp $fn;
my $cmd = "./gtest $fn $fn.out";
print "$cmd\n";
`$cmd`;
my $res = system("diff -u $fn.ref $fn.out");
push @res, [$fn, ($res == 0 ? "OK" : "*KO*")];
}
format =
@<<<<<<<<<<<<<<<<<<<<<<<<<< @>>>
$_->[0], $_->[1]
.
#format_name STDOUT test_result;
map { write; } @res;

View File

@ -302,11 +302,6 @@ struct connection* udp_c2s_forward(int sockfd, struct loop_info* fd_info)
cnx->addrlen = addrlen;
cnx->local_endpoint = sockfd;
if (inc_proto_connections(cnx)) {
tidy_connection(cnx, fd_info);
return NULL;
}
res = new_source(fd_info->hash_sources, cnx);
if (res == -1) {
print_message(msg_connections_error, "Out of hash space for new incoming UDP connection -- increase udp_max_connections");