mirror of
https://github.com/yrutschle/sslh.git
synced 2025-08-11 21:11:36 +03:00
Compare commits
30 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
8aa97d7118 | ||
|
8ad8bfdb5d | ||
|
4c2e4e01f2 | ||
|
2ecb681277 | ||
|
54dc8374ab | ||
|
8c4253f145 | ||
|
4483e9c7e5 | ||
|
65c9c4ce95 | ||
|
5434dc59df | ||
|
20290bbfa6 | ||
|
1dfd70c20c | ||
|
feaf528a60 | ||
|
11da63cf4e | ||
|
28ea73301e | ||
|
cd9b85fd4f | ||
|
bd9ed060e4 | ||
|
b7556c07bd | ||
|
6b9ec3a46e | ||
|
ad66e79f46 | ||
|
b12220e640 | ||
|
204305a88f | ||
|
0f96ed8adb | ||
|
43e75a0a8c | ||
|
ad1f5d68e9 | ||
|
ff8206f7c8 | ||
|
8298daf686 | ||
|
168477ea34 | ||
|
b5d4d4662b | ||
|
6e6d94752a | ||
|
b2bcfc26b2 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,6 +10,7 @@ sslh-ev
|
|||||||
systemd-sslh-generator
|
systemd-sslh-generator
|
||||||
sslh.8.gz
|
sslh.8.gz
|
||||||
tags
|
tags
|
||||||
|
version.h
|
||||||
/config.status
|
/config.status
|
||||||
/config.log
|
/config.log
|
||||||
/config.h
|
/config.h
|
||||||
|
30
ChangeLog
30
ChangeLog
@ -1,3 +1,33 @@
|
|||||||
|
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
|
||||||
|
every time) and the release archive creation (which
|
||||||
|
relies on git tags).
|
||||||
|
|
||||||
v2.2.2:
|
v2.2.2:
|
||||||
Fix potential vulnerability similar to CVE-2020-28935
|
Fix potential vulnerability similar to CVE-2020-28935
|
||||||
|
|
||||||
|
10
Makefile.in
10
Makefile.in
@ -22,7 +22,7 @@ MAN=sslh.8.gz # man page name
|
|||||||
# itself
|
# itself
|
||||||
|
|
||||||
ifneq ($(strip $(ENABLE_SANITIZER)),)
|
ifneq ($(strip $(ENABLE_SANITIZER)),)
|
||||||
CFLAGS_SAN=-fsanitize=address -fsanitize=leak -fsanitize=undefined
|
CFLAGS_SAN=-fsanitize=address -fsanitize=leak -fsanitize=undefined -fsanitize=alignment
|
||||||
endif
|
endif
|
||||||
|
|
||||||
ifneq ($(strip $(COV_TEST)),)
|
ifneq ($(strip $(COV_TEST)),)
|
||||||
@ -70,9 +70,8 @@ all: sslh-fork sslh-select $(MAN) echosrv $(CONDITIONAL_TARGETS)
|
|||||||
$(OBJS_A): $(OBJS)
|
$(OBJS_A): $(OBJS)
|
||||||
$(AR) rcs $(OBJS_A) $(OBJS)
|
$(AR) rcs $(OBJS_A) $(OBJS)
|
||||||
|
|
||||||
version.h: .FORCE
|
version.h:
|
||||||
./genver.sh >version.h
|
./genver.sh >version.h
|
||||||
.FORCE:
|
|
||||||
|
|
||||||
$(OBJS) $(FORK_OBJS) $(SELECT_OBJS) $(EV_OBJS): argtable3.h collection.h common.h gap.h hash.h log.h probe.h processes.h sslh-conf.h tcp-listener.h tcp-probe.h tls.h udp-listener.h version.h
|
$(OBJS) $(FORK_OBJS) $(SELECT_OBJS) $(EV_OBJS): argtable3.h collection.h common.h gap.h hash.h log.h probe.h processes.h sslh-conf.h tcp-listener.h tcp-probe.h tls.h udp-listener.h version.h
|
||||||
|
|
||||||
@ -145,10 +144,9 @@ distclean: clean
|
|||||||
|
|
||||||
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
|
rm -f sslh-fork sslh-select $(CONDITIONAL_TARGETS) echosrv version.h $(MAN) systemd-sslh-generator *.o *.gcov *.gcno *.gcda *.png *.html *.css *.info
|
||||||
echo "// this is a placeholder for version.h, to make code-checking editors happy" > version.h
|
|
||||||
|
|
||||||
tags:
|
tags: *.c *.h
|
||||||
ctags --globals -T *.[ch]
|
ctags *.[ch]
|
||||||
|
|
||||||
cscope:
|
cscope:
|
||||||
-find . -name "*.[chS]" >cscope.files
|
-find . -name "*.[chS]" >cscope.files
|
||||||
|
15
README.md
15
README.md
@ -30,6 +30,20 @@ Install
|
|||||||
|
|
||||||
Please refer to the [install guide](doc/INSTALL.md).
|
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
|
Configuration
|
||||||
=============
|
=============
|
||||||
@ -59,6 +73,7 @@ interfaces. The principle and basic setup is described
|
|||||||
[here](doc/simple_transparent_proxy.md), with further
|
[here](doc/simple_transparent_proxy.md), with further
|
||||||
scenarios described [there](doc/scenarios-for-simple-transparent-proxy.md).
|
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
|
Another method uses iptable packet marking features, and is
|
||||||
highly dependent on your network environment and
|
highly dependent on your network environment and
|
||||||
|
48
common.c
48
common.c
@ -185,6 +185,7 @@ 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].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].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
||||||
(*sockfd)[num_addr-1].family = AF_INET;
|
(*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),
|
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->keepalive ? "keepalive" : "",
|
||||||
cfg->is_udp ? "udp" : "");
|
cfg->is_udp ? "udp" : "");
|
||||||
@ -219,6 +220,7 @@ static int start_listen_unix(struct listen_endpoint *sockfd[], int num_addr, str
|
|||||||
(*sockfd)[num_addr-1].socketfd = fd;
|
(*sockfd)[num_addr-1].socketfd = fd;
|
||||||
(*sockfd)[num_addr-1].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
(*sockfd)[num_addr-1].type = cfg->is_udp ? SOCK_DGRAM : SOCK_STREAM;
|
||||||
(*sockfd)[num_addr-1].family = AF_INET;
|
(*sockfd)[num_addr-1].family = AF_INET;
|
||||||
|
(*sockfd)[num_addr-1].endpoint_cfg = cfg;
|
||||||
|
|
||||||
return num_addr;
|
return num_addr;
|
||||||
}
|
}
|
||||||
@ -595,6 +597,37 @@ 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
|
* moves data from one fd to other
|
||||||
*
|
*
|
||||||
@ -849,16 +882,23 @@ int check_access_rights(int in_socket, const char* service)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
volatile sig_atomic_t received_sigchld;
|
||||||
|
|
||||||
|
void sig_sigchld(int sig)
|
||||||
|
{
|
||||||
|
received_sigchld = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void setup_signals(void)
|
void setup_signals(void)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
struct sigaction action;
|
struct sigaction action;
|
||||||
|
|
||||||
/* Request no SIGCHLD is sent upon termination of
|
/* Set SIGCHLD to sig_sigchld() */
|
||||||
* the children */
|
|
||||||
memset(&action, 0, sizeof(action));
|
memset(&action, 0, sizeof(action));
|
||||||
action.sa_handler = NULL;
|
action.sa_handler = sig_sigchld;
|
||||||
action.sa_flags = SA_NOCLDWAIT;
|
action.sa_flags = SA_NOCLDSTOP;
|
||||||
res = sigaction(SIGCHLD, &action, NULL);
|
res = sigaction(SIGCHLD, &action, NULL);
|
||||||
CHECK_RES_DIE(res, "sigaction");
|
CHECK_RES_DIE(res, "sigaction");
|
||||||
|
|
||||||
|
8
common.h
8
common.h
@ -109,6 +109,7 @@ struct connection {
|
|||||||
struct sslhcfg_protocols_item* proto; /* Where to connect to */
|
struct sslhcfg_protocols_item* proto; /* Where to connect to */
|
||||||
|
|
||||||
/* SOCK_STREAM */
|
/* SOCK_STREAM */
|
||||||
|
struct listen_endpoint* endpoint; /* Client-facing listen fd */
|
||||||
enum connection_state state;
|
enum connection_state state;
|
||||||
time_t probe_timeout;
|
time_t probe_timeout;
|
||||||
|
|
||||||
@ -138,6 +139,8 @@ struct listen_endpoint {
|
|||||||
int socketfd; /* file descriptor of listening socket */
|
int socketfd; /* file descriptor of listening socket */
|
||||||
int type; /* SOCK_DGRAM | SOCK_STREAM */
|
int type; /* SOCK_DGRAM | SOCK_STREAM */
|
||||||
int family; /* AF_INET | AF_UNIX */
|
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
|
#define FD_CNXCLOSED 0
|
||||||
@ -174,6 +177,8 @@ void drop_privileges(const char* user_name, const char* chroot_path);
|
|||||||
void set_capabilities(int cap_net_admin);
|
void set_capabilities(int cap_net_admin);
|
||||||
void write_pid_file(const char* pidfile);
|
void write_pid_file(const char* pidfile);
|
||||||
void dump_connection(struct connection *cnx);
|
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 resolve_split_name(struct addrinfo **out, char* hostname, char* port);
|
||||||
|
|
||||||
int start_listen_sockets(struct listen_endpoint *sockfd[]);
|
int start_listen_sockets(struct listen_endpoint *sockfd[]);
|
||||||
@ -199,4 +204,7 @@ void main_loop(struct listen_endpoint *listen_sockets, int num_addr_listen);
|
|||||||
void setup_landlock(void);
|
void setup_landlock(void);
|
||||||
|
|
||||||
|
|
||||||
|
/* sslh-fork.c or processes.c, depending on the model */
|
||||||
|
void setup_sigchld(void);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -200,3 +200,12 @@ process both single-datagram protocols such as DNS, and
|
|||||||
connection-based protocols such as QUIC.
|
connection-based protocols such as QUIC.
|
||||||
|
|
||||||
An example for supporting QUIC is shown in `example.cfg`.
|
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).
|
||||||
|
55
doc/max_connections.md
Normal file
55
doc/max_connections.md
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
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.
|
120
doc/podman.md
Normal file
120
doc/podman.md
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
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.
|
||||||
|
|
@ -1,5 +1,5 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||||
* on Sun Apr 6 11:44:59 2025.
|
* on Wed Jul 16 17:59:23 2025.
|
||||||
|
|
||||||
# conf2struct: generate libconf parsers that read to structs
|
# conf2struct: generate libconf parsers that read to structs
|
||||||
# Copyright (C) 2018-2024 Yves Rutschle
|
# Copyright (C) 2018-2024 Yves Rutschle
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||||
* on Sun Apr 6 11:44:59 2025.
|
* on Wed Jul 16 17:59:23 2025.
|
||||||
|
|
||||||
# conf2struct: generate libconf parsers that read to structs
|
# conf2struct: generate libconf parsers that read to structs
|
||||||
# Copyright (C) 2018-2024 Yves Rutschle
|
# Copyright (C) 2018-2024 Yves Rutschle
|
||||||
|
@ -26,7 +26,6 @@
|
|||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
#include <syslog.h>
|
#include <syslog.h>
|
||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <getopt.h>
|
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
|
|
||||||
#define cfg sslhcfg
|
#define cfg sslhcfg
|
||||||
@ -323,9 +322,6 @@ int start_listen_sockets(struct listen_endpoint *sockfd[])
|
|||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
|
|
||||||
extern char *optarg;
|
|
||||||
extern int optind;
|
|
||||||
int num_addr_listen;
|
int num_addr_listen;
|
||||||
|
|
||||||
struct listen_endpoint *listen_sockets;
|
struct listen_endpoint *listen_sockets;
|
||||||
|
14
example.cfg
14
example.cfg
@ -49,9 +49,15 @@ syslog_facility: "auth";
|
|||||||
|
|
||||||
# List of interfaces on which we should listen
|
# List of interfaces on which we should listen
|
||||||
# Options:
|
# 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:
|
listen:
|
||||||
(
|
(
|
||||||
{ host: "thelonious"; port: "443"; },
|
{ host: "thelonious"; port: "443"; max_connections: 5; },
|
||||||
{ host: "thelonious"; port: "8080"; keepalive: true; },
|
{ host: "thelonious"; port: "8080"; keepalive: true; },
|
||||||
{ host: "thelonious"; is_udp: true; port: "443"; },
|
{ host: "thelonious"; is_udp: true; port: "443"; },
|
||||||
{ host: "/tmp/unix_socket"; is_unix: true; port: ""; }
|
{ host: "/tmp/unix_socket"; is_unix: true; port: ""; }
|
||||||
@ -70,7 +76,11 @@ listen:
|
|||||||
# keepalive: Should TCP keepalive be on or off for that
|
# keepalive: Should TCP keepalive be on or off for that
|
||||||
# connection (default is off)
|
# connection (default is off)
|
||||||
# fork: Should a new process be forked for this protocol?
|
# fork: Should a new process be forked for this protocol?
|
||||||
# (only useful for sslh-select)
|
# (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).
|
||||||
# tfo_ok: Set to true if the server supports TCP FAST OPEN
|
# 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
|
# resolve_on_forward: Set to true if server address should be resolved on
|
||||||
# (every) newly incoming connection (again)
|
# (every) newly incoming connection (again)
|
||||||
|
14
gap.c
14
gap.c
@ -59,6 +59,11 @@ gap_array* gap_init(int len)
|
|||||||
return gap;
|
return gap;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void gap_set_hardlimit(gap_array* gap, int index)
|
||||||
|
{
|
||||||
|
gap->hardlimit = index;
|
||||||
|
}
|
||||||
|
|
||||||
int gap_extend(gap_array* gap)
|
int gap_extend(gap_array* gap)
|
||||||
{
|
{
|
||||||
int elem_size = sizeof(gap->array[0]);
|
int elem_size = sizeof(gap->array[0]);
|
||||||
@ -88,7 +93,11 @@ void gap_destroy(gap_array* gap)
|
|||||||
* is considered len elements long.
|
* is considered len elements long.
|
||||||
* A poor man's list, if you will. Currently only used to remove probing
|
* A poor man's list, if you will. Currently only used to remove probing
|
||||||
* connections, so it only copies a few pointers at most.
|
* connections, so it only copies a few pointers at most.
|
||||||
* Returns -1 if ptr was not found */
|
* 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)
|
||||||
|
* */
|
||||||
int gap_remove_ptr(gap_array* gap, void* ptr, int len)
|
int gap_remove_ptr(gap_array* gap, void* ptr, int len)
|
||||||
{
|
{
|
||||||
int start, i;
|
int start, i;
|
||||||
@ -102,6 +111,9 @@ int gap_remove_ptr(gap_array* gap, void* ptr, int len)
|
|||||||
else
|
else
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
|
if (gap->len < len)
|
||||||
|
return -2;
|
||||||
|
|
||||||
for (i = start; i < len - 1; i++) {
|
for (i = start; i < len - 1; i++) {
|
||||||
gap->array[i] = gap->array[i+1];
|
gap->array[i] = gap->array[i+1];
|
||||||
}
|
}
|
||||||
|
9
gap.h
9
gap.h
@ -4,6 +4,7 @@
|
|||||||
typedef struct gap_array gap_array;
|
typedef struct gap_array gap_array;
|
||||||
|
|
||||||
gap_array* gap_init(int len);
|
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 void* gap_get(gap_array* gap, int index);
|
||||||
static int gap_set(gap_array* gap, int index, void* ptr);
|
static int gap_set(gap_array* gap, int index, void* ptr);
|
||||||
void gap_destroy(gap_array* gap);
|
void gap_destroy(gap_array* gap);
|
||||||
@ -13,7 +14,8 @@ int gap_remove_ptr(gap_array* gap, void* ptr, int len);
|
|||||||
/* Private declarations to allow inlining.
|
/* Private declarations to allow inlining.
|
||||||
* Don't assume my implementation. */
|
* Don't assume my implementation. */
|
||||||
typedef struct gap_array {
|
typedef struct gap_array {
|
||||||
int len; /* Number of elements in 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 */
|
||||||
void** array;
|
void** array;
|
||||||
} gap_array;
|
} gap_array;
|
||||||
|
|
||||||
@ -21,6 +23,9 @@ int gap_extend(gap_array* gap);
|
|||||||
|
|
||||||
static inline int __attribute__((unused)) gap_set(gap_array* gap, int index, void* ptr)
|
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) {
|
while (index >= gap->len) {
|
||||||
int res = gap_extend(gap);
|
int res = gap_extend(gap);
|
||||||
if (res == -1) return -1;
|
if (res == -1) return -1;
|
||||||
@ -37,6 +42,8 @@ static inline void* __attribute__((unused)) gap_get(gap_array* gap, int index)
|
|||||||
* gap_get()'s job. This will do for now */
|
* gap_get()'s job. This will do for now */
|
||||||
if (index >= gap->len) return NULL;
|
if (index >= gap->len) return NULL;
|
||||||
|
|
||||||
|
if (gap->hardlimit && (index > gap->hardlimit)) return NULL;
|
||||||
|
|
||||||
return gap->array[index];
|
return gap->array[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
63
probe.c
63
probe.c
@ -21,10 +21,7 @@
|
|||||||
|
|
||||||
#define _GNU_SOURCE
|
#define _GNU_SOURCE
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#ifdef ENABLE_REGEX
|
#include <regex.h>
|
||||||
#define PCRE2_CODE_UNIT_WIDTH 8
|
|
||||||
#include <pcre2.h>
|
|
||||||
#endif
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include "probe.h"
|
#include "probe.h"
|
||||||
#include "log.h"
|
#include "log.h"
|
||||||
@ -146,6 +143,7 @@ static int is_ssh_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_
|
|||||||
#define OVPN_OPCODE_MASK 0xF8
|
#define OVPN_OPCODE_MASK 0xF8
|
||||||
#define OVPN_CONTROL_HARD_RESET_CLIENT_V1 (0x01 << 3)
|
#define OVPN_CONTROL_HARD_RESET_CLIENT_V1 (0x01 << 3)
|
||||||
#define OVPN_CONTROL_HARD_RESET_CLIENT_V2 (0x07 << 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_128 16
|
||||||
#define OVPN_HMAC_160 20
|
#define OVPN_HMAC_160 20
|
||||||
#define OVPN_HARD_RESET_PACKET_ID_OFFSET(hmac_size) (9 + hmac_size)
|
#define OVPN_HARD_RESET_PACKET_ID_OFFSET(hmac_size) (9 + hmac_size)
|
||||||
@ -164,8 +162,12 @@ static int is_openvpn_protocol (const char*p,ssize_t len, struct sslhcfg_protoco
|
|||||||
if (len < 1)
|
if (len < 1)
|
||||||
return PROBE_NEXT;
|
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 &&
|
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_V2 &&
|
||||||
|
(p[0] & OVPN_OPCODE_MASK) != OVPN_CONTROL_HARD_RESET_CLIENT_V3
|
||||||
|
)
|
||||||
return PROBE_NEXT;
|
return PROBE_NEXT;
|
||||||
|
|
||||||
/* The detection pattern above may not be reliable enough.
|
/* The detection pattern above may not be reliable enough.
|
||||||
@ -176,13 +178,19 @@ 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))
|
if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128) + sizeof(uint32_t))
|
||||||
return PROBE_NEXT;
|
return PROBE_NEXT;
|
||||||
|
|
||||||
if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_128))) <= 5u)
|
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)
|
||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
|
|
||||||
if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160) + sizeof(uint32_t))
|
if (len <= OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160) + sizeof(uint32_t))
|
||||||
return PROBE_NEXT;
|
return PROBE_NEXT;
|
||||||
|
|
||||||
if (ntohl(*(uint32_t*)(p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160))) <= 5u)
|
memcpy(&i, (p + OVPN_HARD_RESET_PACKET_ID_OFFSET(OVPN_HMAC_160)), sizeof(i));
|
||||||
|
i = ntohl(i);
|
||||||
|
if (i <= 5u)
|
||||||
return PROBE_MATCH;
|
return PROBE_MATCH;
|
||||||
|
|
||||||
return PROBE_NEXT;
|
return PROBE_NEXT;
|
||||||
@ -362,17 +370,38 @@ static int is_socks5_protocol(const char *p_in, ssize_t len, struct sslhcfg_prot
|
|||||||
return PROBE_MATCH;
|
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)
|
static int is_syslog_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
|
||||||
{
|
{
|
||||||
int res, i, j;
|
char buf[len+1];
|
||||||
|
|
||||||
res = sscanf(p, "<%d>", &i);
|
if (!configured_syslog_regex) config_syslog_regex();
|
||||||
if (res == 1) return 1;
|
|
||||||
|
|
||||||
res = sscanf(p, "%d <%d>", &i, &j);
|
strncpy(buf, p, len);
|
||||||
if (res == 2) return 1;
|
buf[len] = 0;
|
||||||
|
|
||||||
return 0;
|
return (regexec(&syslog_preg, buf, (size_t)0, NULL, 0) == 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int is_teamspeak_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
|
static int is_teamspeak_protocol(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
|
||||||
@ -396,16 +425,18 @@ static int is_msrdp_protocol(const char *p, ssize_t len, struct sslhcfg_protocol
|
|||||||
return packet_len == len;
|
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)
|
static int regex_probe(const char *p, ssize_t len, struct sslhcfg_protocols_item* proto)
|
||||||
{
|
{
|
||||||
#ifdef ENABLE_REGEX
|
#ifdef ENABLE_REGEX
|
||||||
pcre2_code**probe = (pcre2_code**)proto->data;
|
pcre2_code**probe = (pcre2_code**)proto->data;
|
||||||
pcre2_match_data* matches;
|
|
||||||
|
|
||||||
matches = pcre2_match_data_create(1, NULL);
|
|
||||||
|
|
||||||
for (; *probe; probe++) {
|
for (; *probe; probe++) {
|
||||||
int res = pcre2_match(*probe, (PCRE2_SPTR8)p, len, 0, 0, matches, NULL);
|
int res = pcre2_match(*probe, (PCRE2_SPTR8)p, len, 0, 0, probe_regex_matches, NULL);
|
||||||
if (res >= 0) return 1;
|
if (res >= 0) return 1;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
7
probe.h
7
probe.h
@ -66,4 +66,11 @@ struct sslhcfg_protocols_item* timeout_protocol(void);
|
|||||||
|
|
||||||
void hexdump(msg_info, const char*, unsigned int);
|
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
|
#endif
|
||||||
|
@ -49,6 +49,9 @@ 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)
|
if (gap_remove_ptr(fd_info->probing_list, cnx, fd_info->num_probing) != -1)
|
||||||
fd_info->num_probing--;
|
fd_info->num_probing--;
|
||||||
|
|
||||||
|
dec_proto_connections(cnx);
|
||||||
|
dec_listen_connections(cnx);
|
||||||
|
|
||||||
collection_remove_cnx(fd_info->collection, cnx);
|
collection_remove_cnx(fd_info->collection, cnx);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -90,7 +93,7 @@ struct connection* cnx_accept_process(struct loop_info* fd_info, struct listen_e
|
|||||||
|
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case SOCK_STREAM:
|
case SOCK_STREAM:
|
||||||
cnx = accept_new_connection(fd, fd_info);
|
cnx = accept_new_connection(listen_socket, fd_info);
|
||||||
if (!cnx) return NULL;
|
if (!cnx) return NULL;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
@ -50,22 +50,38 @@ static int family_to_pp(int af_family)
|
|||||||
|
|
||||||
typedef char libpp_addr[108]; /* This is hardcoded in libproxyprotocol/proxy_protocol.h */
|
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
|
/* Fills *addr, *host and *serv with the connection information corresponding
|
||||||
* to fd. *host is the IP address as string and *serv is the service (port)
|
* 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)
|
||||||
* */
|
* */
|
||||||
static int get_info(int fd, struct addrinfo* addr, libpp_addr* host, uint16_t* serv)
|
static int get_info(int fd, sockpeer_t sockpeer, struct addrinfo* addr, libpp_addr* host, uint16_t* serv)
|
||||||
{
|
{
|
||||||
char serv_str[NI_MAXSERV];
|
char serv_str[NI_MAXSERV];
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
res = getpeername(fd, addr->ai_addr, &addr->ai_addrlen);
|
if (sockpeer == PEER) {
|
||||||
CHECK_RES_RETURN(res, "getpeername", -1);
|
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,
|
res = getnameinfo(addr->ai_addr, addr->ai_addrlen,
|
||||||
(char*)host, sizeof(*host),
|
(char*)host, sizeof(*host),
|
||||||
serv_str, sizeof(serv_str),
|
serv_str, sizeof(serv_str),
|
||||||
NI_NUMERICHOST | NI_NUMERICSERV );
|
NI_NUMERICHOST | NI_NUMERICSERV );
|
||||||
CHECK_RES_RETURN(res, "getnameinfo", -1);
|
if (res != 0) {
|
||||||
|
print_message(msg_system_error, "getnameinfo: %s\n", gai_strerror(res));
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
*serv = atoi(serv_str);
|
*serv = atoi(serv_str);
|
||||||
|
|
||||||
@ -89,14 +105,14 @@ int pp_write_header(int pp_version, struct connection* cnx)
|
|||||||
addr.ai_addr = (struct sockaddr*)&ss;
|
addr.ai_addr = (struct sockaddr*)&ss;
|
||||||
addr.ai_addrlen = sizeof(ss);
|
addr.ai_addrlen = sizeof(ss);
|
||||||
|
|
||||||
res = get_info(cnx->q[0].fd,
|
res = get_info(cnx->q[0].fd, PEER,
|
||||||
&addr,
|
&addr,
|
||||||
&pp_info_in_v1.src_addr,
|
&pp_info_in_v1.src_addr,
|
||||||
&pp_info_in_v1.src_port);
|
&pp_info_in_v1.src_port);
|
||||||
if (res == -1) return -1;
|
if (res == -1) return -1;
|
||||||
pp_info_in_v1.address_family = family_to_pp(addr.ai_addr->sa_family);
|
pp_info_in_v1.address_family = family_to_pp(addr.ai_addr->sa_family);
|
||||||
|
|
||||||
res = get_info(cnx->q[1].fd,
|
res = get_info(cnx->q[1].fd, SOCK,
|
||||||
&addr,
|
&addr,
|
||||||
&pp_info_in_v1.dst_addr,
|
&pp_info_in_v1.dst_addr,
|
||||||
&pp_info_in_v1.dst_port
|
&pp_info_in_v1.dst_port
|
||||||
|
48
sslh-conf.c
48
sslh-conf.c
@ -1,5 +1,5 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||||
* on Sun Apr 6 11:44:58 2025.
|
* on Mon Aug 4 18:25:44 2025.
|
||||||
|
|
||||||
# conf2struct: generate libconf parsers that read to structs
|
# conf2struct: generate libconf parsers that read to structs
|
||||||
# Copyright (C) 2018-2024 Yves Rutschle
|
# Copyright (C) 2018-2024 Yves Rutschle
|
||||||
@ -500,7 +500,7 @@ struct arg_file* sslhcfg_conffile;
|
|||||||
struct arg_str* sslhcfg_anyprot;
|
struct arg_str* sslhcfg_anyprot;
|
||||||
struct arg_end* sslhcfg_end;
|
struct arg_end* sslhcfg_end;
|
||||||
|
|
||||||
|
|
||||||
static struct config_desc table_sslhcfg_protocols[] = {
|
static struct config_desc table_sslhcfg_protocols[] = {
|
||||||
|
|
||||||
|
|
||||||
@ -712,6 +712,22 @@ static struct config_desc table_sslhcfg_protocols[] = {
|
|||||||
/* default_val*/ .default_val.def_bool = 0
|
/* 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",
|
/* name */ "sni_hostnames",
|
||||||
/* type */ CFG_ARRAY,
|
/* type */ CFG_ARRAY,
|
||||||
@ -793,7 +809,7 @@ static struct config_desc table_sslhcfg_protocols[] = {
|
|||||||
},
|
},
|
||||||
{ 0 }
|
{ 0 }
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct config_desc table_sslhcfg_listen[] = {
|
static struct config_desc table_sslhcfg_listen[] = {
|
||||||
|
|
||||||
|
|
||||||
@ -829,6 +845,22 @@ static struct config_desc table_sslhcfg_listen[] = {
|
|||||||
/* default_val*/ .default_val.def_string = NULL
|
/* 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",
|
/* name */ "is_udp",
|
||||||
/* type */ CFG_BOOL,
|
/* type */ CFG_BOOL,
|
||||||
@ -2421,6 +2453,11 @@ static void sslhcfg_protocols_fprint(
|
|||||||
fprintf(out, "keepalive: %d", sslhcfg_protocols->keepalive);
|
fprintf(out, "keepalive: %d", sslhcfg_protocols->keepalive);
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
indent(out, depth);
|
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);
|
fprintf(out, "sni_hostnames [%zu]:\n", sslhcfg_protocols->sni_hostnames_len);
|
||||||
for (i = 0; i < sslhcfg_protocols->sni_hostnames_len; i++) {
|
for (i = 0; i < sslhcfg_protocols->sni_hostnames_len; i++) {
|
||||||
indent(out, depth+1);
|
indent(out, depth+1);
|
||||||
@ -2463,6 +2500,11 @@ static void sslhcfg_listen_fprint(
|
|||||||
fprintf(out, "port: %s", sslhcfg_listen->port);
|
fprintf(out, "port: %s", sslhcfg_listen->port);
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
indent(out, depth);
|
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, "is_udp: %d", sslhcfg_listen->is_udp);
|
||||||
fprintf(out, "\n");
|
fprintf(out, "\n");
|
||||||
indent(out, depth);
|
indent(out, depth);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
/* Generated by conf2struct (https://www.rutschle.net/tech/conf2struct/README)
|
||||||
* on Sun Apr 6 11:44:58 2025.
|
* on Mon Aug 4 18:25:44 2025.
|
||||||
|
|
||||||
# conf2struct: generate libconf parsers that read to structs
|
# conf2struct: generate libconf parsers that read to structs
|
||||||
# Copyright (C) 2018-2024 Yves Rutschle
|
# Copyright (C) 2018-2024 Yves Rutschle
|
||||||
@ -43,6 +43,8 @@
|
|||||||
struct sslhcfg_listen_item {
|
struct sslhcfg_listen_item {
|
||||||
char* host;
|
char* host;
|
||||||
char* port;
|
char* port;
|
||||||
|
int max_connections_is_present;
|
||||||
|
int max_connections;
|
||||||
int is_udp;
|
int is_udp;
|
||||||
int is_unix;
|
int is_unix;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
@ -63,6 +65,8 @@ struct sslhcfg_protocols_item {
|
|||||||
int resolve_on_forward;
|
int resolve_on_forward;
|
||||||
int log_level;
|
int log_level;
|
||||||
int keepalive;
|
int keepalive;
|
||||||
|
int max_connections_is_present;
|
||||||
|
int max_connections;
|
||||||
size_t sni_hostnames_len;
|
size_t sni_hostnames_len;
|
||||||
char** sni_hostnames;
|
char** sni_hostnames;
|
||||||
size_t alpn_protocols_len;
|
size_t alpn_protocols_len;
|
||||||
@ -76,6 +80,7 @@ struct sslhcfg_protocols_item {
|
|||||||
T_PROBE* probe;
|
T_PROBE* probe;
|
||||||
struct addrinfo* saddr;
|
struct addrinfo* saddr;
|
||||||
void* data;
|
void* data;
|
||||||
|
unsigned int num_connections;
|
||||||
dl_list timeouts;
|
dl_list timeouts;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
54
sslh-fork.c
54
sslh-fork.c
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
sslh-fork: forking server
|
sslh-fork: forking server
|
||||||
|
|
||||||
# Copyright (C) 2007-2021 Yves Rutschle
|
# Copyright (C) 2007-2025 Yves Rutschle
|
||||||
#
|
#
|
||||||
# This program is free software; you can redistribute it
|
# This program is free software; you can redistribute it
|
||||||
# and/or modify it under the terms of the GNU General Public
|
# and/or modify it under the terms of the GNU General Public
|
||||||
@ -160,6 +160,35 @@ void set_listen_procname(struct listen_endpoint *listen_socket)
|
|||||||
#endif
|
#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
|
/* At least MacOS does not know these two options, so define them to something
|
||||||
* equivalent for our use case */
|
* equivalent for our use case */
|
||||||
@ -182,9 +211,9 @@ void tcp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
|
|||||||
while (1) {
|
while (1) {
|
||||||
in_socket = accept(endpoint[active_endpoint].socketfd, 0, 0);
|
in_socket = accept(endpoint[active_endpoint].socketfd, 0, 0);
|
||||||
if (in_socket == -1) {
|
if (in_socket == -1) {
|
||||||
print_message(msg_system_error, "%s:%d:%s:%d:%s\n",
|
print_message(msg_system_error, "%s:%d:%s:%d:%s\n",
|
||||||
__FILE__, __LINE__, "accept", errno, strerror(errno));
|
__FILE__, __LINE__, "accept", errno, strerror(errno));
|
||||||
switch(in_socket) {
|
switch(errno) {
|
||||||
case ENETDOWN: /* accept(2) cites all these errnos as "you should retry" */
|
case ENETDOWN: /* accept(2) cites all these errnos as "you should retry" */
|
||||||
case EPROTO:
|
case EPROTO:
|
||||||
case ENOPROTOOPT:
|
case ENOPROTOOPT:
|
||||||
@ -196,11 +225,24 @@ void tcp_listener(struct listen_endpoint* endpoint, int num_endpoints, int activ
|
|||||||
case ECONNABORTED:
|
case ECONNABORTED:
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
case EINTR:
|
||||||
|
process_signals(endpoint);
|
||||||
|
continue;
|
||||||
|
|
||||||
default: /* Otherwise, it's something wrong in our parameters, we fail */
|
default: /* Otherwise, it's something wrong in our parameters, we fail */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
print_message(msg_fd, "accepted fd %d\n", in_socket);
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
switch(fork()) {
|
switch(fork()) {
|
||||||
case -1: print_message(msg_system_error, "fork failed: err %d: %s\n", errno, strerror(errno));
|
case -1: print_message(msg_system_error, "fork failed: err %d: %s\n", errno, strerror(errno));
|
||||||
@ -250,8 +292,10 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
|
|||||||
exit(0);
|
exit(0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
/* We're in the parent, we don't need to do anything */
|
/* We're in the parent, which does nothing but wait to be killed by
|
||||||
|
* SIGTERM, which it will send to its children */
|
||||||
default:
|
default:
|
||||||
|
mask_sigchld();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,6 +130,7 @@ static void setup_regex_probe(struct sslhcfg_protocols_item *p)
|
|||||||
exit(1);
|
exit(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
probe_regex_matches = pcre2_match_data_create(1, NULL);
|
||||||
}
|
}
|
||||||
#else
|
#else
|
||||||
{
|
{
|
||||||
@ -280,9 +281,6 @@ void close_std(void)
|
|||||||
|
|
||||||
int main(int argc, char *argv[], char* envp[])
|
int main(int argc, char *argv[], char* envp[])
|
||||||
{
|
{
|
||||||
|
|
||||||
extern char *optarg;
|
|
||||||
extern int optind;
|
|
||||||
int res, num_addr_listen;
|
int res, num_addr_listen;
|
||||||
struct listen_endpoint *listen_sockets;
|
struct listen_endpoint *listen_sockets;
|
||||||
|
|
||||||
|
@ -156,13 +156,15 @@ void main_loop(struct listen_endpoint listen_sockets[], int num_addr_listen)
|
|||||||
/* Check main socket for new connections */
|
/* Check main socket for new connections */
|
||||||
for (i = 0; i < num_addr_listen; i++) {
|
for (i = 0; i < num_addr_listen; i++) {
|
||||||
if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) {
|
if (FD_ISSET(listen_sockets[i].socketfd, &readfds)) {
|
||||||
struct connection* 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 */
|
/* don't also process it as a read socket */
|
||||||
FD_CLR(listen_sockets[i].socketfd, &readfds);
|
FD_CLR(listen_sockets[i].socketfd, &readfds);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -97,6 +97,7 @@ config: {
|
|||||||
items: (
|
items: (
|
||||||
{ name: "host"; type: "string"; var: true; },
|
{ name: "host"; type: "string"; var: true; },
|
||||||
{ name: "port"; 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_udp"; type: "bool"; default: false },
|
||||||
{ name: "is_unix"; type: "bool"; default: false },
|
{ name: "is_unix"; type: "bool"; default: false },
|
||||||
{ name: "keepalive"; type: "bool"; default: false; }
|
{ name: "keepalive"; type: "bool"; default: false; }
|
||||||
@ -123,6 +124,7 @@ config: {
|
|||||||
description: "Set to true if server address should be resolved on (every) newly incoming connection (again)" },
|
description: "Set to true if server address should be resolved on (every) newly incoming connection (again)" },
|
||||||
{ name: "log_level"; type: "int"; default: 1 },
|
{ name: "log_level"; type: "int"; default: 1 },
|
||||||
{ name: "keepalive"; type: "bool"; default: false },
|
{ name: "keepalive"; type: "bool"; default: false },
|
||||||
|
{ name: "max_connections"; type: "int"; optional: true },
|
||||||
{ name: "sni_hostnames",
|
{ name: "sni_hostnames",
|
||||||
type: "array",
|
type: "array",
|
||||||
element_type: "string"
|
element_type: "string"
|
||||||
@ -142,6 +144,7 @@ config: {
|
|||||||
{ name: "probe"; type: "runtime"; c_type: "T_PROBE*" },
|
{ name: "probe"; type: "runtime"; c_type: "T_PROBE*" },
|
||||||
{ name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" },
|
{ name: "saddr"; type: "runtime"; c_type: "struct addrinfo*" },
|
||||||
{ name: "data"; type: "runtime"; c_type: "void*" },
|
{ name: "data"; type: "runtime"; c_type: "void*" },
|
||||||
|
{ name: "num_connections"; type: "runtime"; c_type: "unsigned int" },
|
||||||
{ name: "timeouts"; type: "runtime"; c_type: "dl_list" }
|
{ name: "timeouts"; type: "runtime"; c_type: "dl_list" }
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
17
t
17
t
@ -9,7 +9,7 @@
|
|||||||
use strict;
|
use strict;
|
||||||
use IO::Socket::INET6;
|
use IO::Socket::INET6;
|
||||||
use Test::More qw/no_plan/;
|
use Test::More qw/no_plan/;
|
||||||
use Conf::Libconfig;
|
use Conf::Libconfig 1.0.3;
|
||||||
|
|
||||||
my $conf = new Conf::Libconfig;
|
my $conf = new Conf::Libconfig;
|
||||||
$conf->read_file("test.cfg");
|
$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 $no_listen = 8083; # Port on which no-one listens
|
||||||
my $pidfile = $conf->lookup_value("pidfile");
|
my $pidfile = $conf->lookup_value("pidfile");
|
||||||
my $sslh_port = $conf->fetch_array("listen")->[0]->{port};
|
my $sslh_port = $conf->value("listen")->[0]->{port};
|
||||||
my $user = (getpwuid $<)[0]; # Run under current username
|
my $user = (getpwuid $<)[0]; # Run under current username
|
||||||
|
|
||||||
# Which tests do we run
|
# Which tests do we run
|
||||||
@ -84,8 +84,9 @@ sub make_sni_alpn_name {
|
|||||||
sub test_probe {
|
sub test_probe {
|
||||||
my (%opts) = @_;
|
my (%opts) = @_;
|
||||||
|
|
||||||
|
print "test_probe [$opts{expected}] $sslh_port\n";
|
||||||
my $cnx = new IO::Socket::INET(PeerHost => "localhost:$sslh_port");
|
my $cnx = new IO::Socket::INET(PeerHost => "localhost:$sslh_port");
|
||||||
warn "$!\n" unless $cnx;
|
warn "t: $!\n" unless $cnx;
|
||||||
return unless $cnx;
|
return unless $cnx;
|
||||||
|
|
||||||
my $pattern = $opts{data};
|
my $pattern = $opts{data};
|
||||||
@ -119,7 +120,7 @@ sub test_probe {
|
|||||||
sub test_probes {
|
sub test_probes {
|
||||||
my (%in_opts) = @_;
|
my (%in_opts) = @_;
|
||||||
|
|
||||||
my @probes = @{$conf->fetch_array("protocols")};
|
my @probes = @{$conf->value("protocols")};
|
||||||
foreach my $p (@probes) {
|
foreach my $p (@probes) {
|
||||||
my %protocols = (
|
my %protocols = (
|
||||||
'ssh' => { data => "SSH-2.0 tester" },
|
'ssh' => { data => "SSH-2.0 tester" },
|
||||||
@ -194,7 +195,7 @@ sub test_probes {
|
|||||||
|
|
||||||
|
|
||||||
# Start an echoserver for each service
|
# Start an echoserver for each service
|
||||||
foreach my $s (@{$conf->fetch_array("protocols")}) {
|
foreach my $s (@{$conf->value("protocols")}) {
|
||||||
my $prefix = $s->{name};
|
my $prefix = $s->{name};
|
||||||
|
|
||||||
$prefix =~ s/^ssl/tls/; # To remove in 1.21
|
$prefix =~ s/^ssl/tls/; # To remove in 1.21
|
||||||
@ -217,7 +218,7 @@ for my $binary (@binaries) {
|
|||||||
my ($sslh_pid, $valgrind);
|
my ($sslh_pid, $valgrind);
|
||||||
if (!($sslh_pid = fork)) {
|
if (!($sslh_pid = fork)) {
|
||||||
my $user = (getpwuid $<)[0]; # Run under current username
|
my $user = (getpwuid $<)[0]; # Run under current username
|
||||||
my $cmd = "./$binary -v 4 -f -u $user -F test.cfg";
|
my $cmd = "./$binary -u $user -F test.cfg";
|
||||||
#$valgrind = 1;
|
#$valgrind = 1;
|
||||||
#$cmd = "valgrind --leak-check=full $cmd";
|
#$cmd = "valgrind --leak-check=full $cmd";
|
||||||
verbose_exec $cmd;
|
verbose_exec $cmd;
|
||||||
@ -339,11 +340,11 @@ if ($RB_CNX_NOSERVER) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
my $ssh_conf = (grep { $_->{name} eq "ssh" } @{$conf->fetch_array("protocols")})[0];
|
my $ssh_conf = (grep { $_->{name} eq "ssh" } @{$conf->value("protocols")})[0];
|
||||||
my $ssh_address = $ssh_conf->{host} . ":" . $ssh_conf->{port};
|
my $ssh_address = $ssh_conf->{host} . ":" . $ssh_conf->{port};
|
||||||
|
|
||||||
# Use the last TLS echoserv (no SNI/ALPN)
|
# Use the last TLS echoserv (no SNI/ALPN)
|
||||||
my $ssl_conf = (grep { $_->{name} eq "tls" } @{$conf->fetch_array("protocols")})[-1];
|
my $ssl_conf = (grep { $_->{name} eq "tls" } @{$conf->value ("protocols")})[-1];
|
||||||
my $ssl_address = $ssl_conf->{host} . ":" . $ssl_conf->{port};
|
my $ssl_address = $ssl_conf->{host} . ":" . $ssl_conf->{port};
|
||||||
|
|
||||||
|
|
||||||
|
@ -118,12 +118,45 @@ 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.
|
/* 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
|
* If no slots are available, allocate another few. If that fails, drop the
|
||||||
* connexion */
|
* connexion */
|
||||||
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info)
|
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info)
|
||||||
{
|
{
|
||||||
int in_socket, res;
|
int in_socket, res;
|
||||||
|
int listen_socket = endpoint->socketfd;
|
||||||
|
|
||||||
print_message(msg_fd, "accepting from %d\n", listen_socket);
|
print_message(msg_fd, "accepting from %d\n", listen_socket);
|
||||||
|
|
||||||
@ -141,12 +174,16 @@ struct connection* accept_new_connection(int listen_socket, struct loop_info* fd
|
|||||||
close(in_socket);
|
close(in_socket);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
cnx->endpoint = endpoint;
|
||||||
|
if (inc_listen_connections(cnx)) {
|
||||||
|
tidy_connection(cnx, fd_info);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
add_probing_cnx(fd_info, cnx);
|
add_probing_cnx(fd_info, cnx);
|
||||||
return cnx;
|
return cnx;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Connect queue 1 of connection to SSL; returns new file descriptor */
|
/* Connect queue 1 of connection to SSL; returns new file descriptor */
|
||||||
static int connect_queue(struct connection* cnx,
|
static int connect_queue(struct connection* cnx,
|
||||||
struct loop_info* fd_info)
|
struct loop_info* fd_info)
|
||||||
@ -276,6 +313,11 @@ void probing_read_process(struct connection* cnx,
|
|||||||
remove_probing_cnx(fd_info, cnx);
|
remove_probing_cnx(fd_info, cnx);
|
||||||
cnx->state = ST_SHOVELING;
|
cnx->state = ST_SHOVELING;
|
||||||
|
|
||||||
|
if (inc_proto_connections(cnx)) {
|
||||||
|
tidy_connection(cnx, fd_info);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
/* libwrap check if required for this protocol */
|
/* libwrap check if required for this protocol */
|
||||||
if (cnx->proto->service &&
|
if (cnx->proto->service &&
|
||||||
check_access_rights(cnx->q[0].fd, cnx->proto->service)) {
|
check_access_rights(cnx->q[0].fd, cnx->proto->service)) {
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
#include "tcp-probe.h"
|
#include "tcp-probe.h"
|
||||||
|
|
||||||
void tcp_read_process(struct loop_info* fd_info, int fd);
|
void tcp_read_process(struct loop_info* fd_info, int fd);
|
||||||
struct connection* accept_new_connection(int listen_socket, struct loop_info* fd_info);
|
struct connection* accept_new_connection(struct listen_endpoint* endpoint, struct loop_info* fd_info);
|
||||||
void probing_read_process(struct connection* cnx, 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 cnx_write_process(struct loop_info* fd_info, int fd);
|
||||||
|
|
||||||
|
void dec_listen_connections(struct connection* cnx);
|
||||||
#endif
|
#endif
|
||||||
|
21
test.cfg
21
test.cfg
@ -19,7 +19,7 @@ verbose-config-error: 1; # print configuration errors
|
|||||||
verbose-connections: 1; # trace established incoming address to forward address
|
verbose-connections: 1; # trace established incoming address to forward address
|
||||||
verbose-connections-error: 1; # connection errors
|
verbose-connections-error: 1; # connection errors
|
||||||
verbose-connections-try: 1; # connection attempts towards targets
|
verbose-connections-try: 1; # connection attempts towards targets
|
||||||
verbose-fd: 0; # file descriptor activity, open/close/whatnot
|
verbose-fd: 1; # file descriptor activity, open/close/whatnot
|
||||||
verbose-packets: 1; # hexdump packets on which probing is done
|
verbose-packets: 1; # hexdump packets on which probing is done
|
||||||
verbose-probe-info: 0; # what's happening during the probe process
|
verbose-probe-info: 0; # what's happening during the probe process
|
||||||
verbose-probe-error: 1; # failures and problems during probing
|
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:
|
# Options:
|
||||||
listen:
|
listen:
|
||||||
(
|
(
|
||||||
{ host: "localhost"; port: "8080"; keepalive: true; },
|
{ host: "localhost"; port: "8080"; keepalive: true; max_connections: 2; },
|
||||||
{ host: "localhost"; port: "8081"; 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: ""; }
|
{ host: "/tmp/sslh.sock"; is_unix: true; port: ""; }
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -43,7 +43,8 @@ listen:
|
|||||||
|
|
||||||
protocols:
|
protocols:
|
||||||
(
|
(
|
||||||
{ name: "ssh"; host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true; },
|
{ name: "ssh"; host: "localhost"; port: "9000"; fork: true; transparent: true; resolve_on_forward: true;
|
||||||
|
max_connections: 1; },
|
||||||
{ name: "socks5"; host: "localhost"; port: "9001"; },
|
{ name: "socks5"; host: "localhost"; port: "9001"; },
|
||||||
{ name: "http"; host: "localhost"; port: "80"; proxyprotocol: 2; },
|
{ name: "http"; host: "localhost"; port: "80"; proxyprotocol: 2; },
|
||||||
{ name: "tinc"; host: "localhost"; port: "9003"; },
|
{ name: "tinc"; host: "localhost"; port: "9003"; },
|
||||||
@ -51,11 +52,12 @@ protocols:
|
|||||||
{ name: "xmpp"; host: "localhost"; port: "9009"; },
|
{ name: "xmpp"; host: "localhost"; port: "9009"; },
|
||||||
{ name: "adb"; host: "localhost"; port: "9010"; },
|
{ name: "adb"; host: "localhost"; port: "9010"; },
|
||||||
{ name: "syslog"; host: "localhost"; port: "9013"; },
|
{ name: "syslog"; host: "localhost"; port: "9013"; },
|
||||||
{ name: "regex"; host: "ip4-localhost"; is_udp: true; port: "9020";
|
# { name: "regex"; host: "ip4-localhost"; is_udp: true; port: "9020";
|
||||||
udp_timeout: 30;
|
# max_connections: 1;
|
||||||
regex_patterns: [ "^foo" ];
|
# udp_timeout: 30;
|
||||||
resolve_on_forward: true;
|
# regex_patterns: [ "^foo" ];
|
||||||
},
|
# resolve_on_forward: true;
|
||||||
|
# },
|
||||||
{ name: "regex"; host: "localhost"; port: "9011";
|
{ name: "regex"; host: "localhost"; port: "9011";
|
||||||
regex_patterns: [ "^foo", "^bar" ];
|
regex_patterns: [ "^foo", "^bar" ];
|
||||||
minlength: 4;
|
minlength: 4;
|
||||||
@ -72,6 +74,7 @@ protocols:
|
|||||||
{ name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; },
|
{ name: "tls"; host: "localhost"; port: "9023"; alpn_protocols: [ "alpn3" ]; },
|
||||||
{ name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; },
|
{ name: "tls"; host: "localhost"; port: "9024"; sni_hostnames: [ "sni3" ]; },
|
||||||
{ name: "tls"; host: "localhost"; port: "9025"; },
|
{ name: "tls"; host: "localhost"; port: "9025"; },
|
||||||
|
# { name: "anyprot"; host: "ip4-localhost"; is_udp: true; port: "9999"; },
|
||||||
{ name: "anyprot"; host: "localhost"; port: "9099"; }
|
{ name: "anyprot"; host: "localhost"; port: "9099"; }
|
||||||
);
|
);
|
||||||
|
|
||||||
|
7
testgap/Makefile
Normal file
7
testgap/Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
|
||||||
|
CFLAGS=-DHASH_TESTING -O2 -Wall
|
||||||
|
OBJ=../gap.o gtest.o
|
||||||
|
|
||||||
|
gtest: $(OBJ)
|
||||||
|
$(CC) -o gtest $(OBJ)
|
||||||
|
|
102
testgap/gtest.c
Normal file
102
testgap/gtest.c
Normal file
@ -0,0 +1,102 @@
|
|||||||
|
/* 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;
|
||||||
|
}
|
11
testgap/hardlimit.tst
Normal file
11
testgap/hardlimit.tst
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
|
||||||
|
# Test hard limit
|
||||||
|
|
||||||
|
h 15 0 # set hard limit
|
||||||
|
a 5 42
|
||||||
|
a 6 43
|
||||||
|
a 15 44
|
||||||
|
a 16 45
|
||||||
|
a 17 46
|
||||||
|
|
||||||
|
|
514
testgap/hardlimit.tst.ref
Normal file
514
testgap/hardlimit.tst.ref
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
<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>
|
5
testgap/insert_extend.tst
Normal file
5
testgap/insert_extend.tst
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
# Insertions after the first page, to extend the gap
|
||||||
|
|
||||||
|
a 5 42
|
||||||
|
a 1024 43
|
||||||
|
a 1028 44
|
1538
testgap/insert_extend.tst.ref
Normal file
1538
testgap/insert_extend.tst.ref
Normal file
File diff suppressed because it is too large
Load Diff
6
testgap/inserts.tst
Normal file
6
testgap/inserts.tst
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
# Simple insertions in the first page
|
||||||
|
|
||||||
|
a 5 42
|
||||||
|
a 10 43
|
||||||
|
|
||||||
|
|
514
testgap/inserts.tst.ref
Normal file
514
testgap/inserts.tst.ref
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
<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>
|
10
testgap/remove.tst
Normal file
10
testgap/remove.tst
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
# Remove values
|
||||||
|
|
||||||
|
a 5 42
|
||||||
|
a 10 43
|
||||||
|
a 13 44
|
||||||
|
a 510 45
|
||||||
|
a 511 46
|
||||||
|
|
||||||
|
d 512 43
|
||||||
|
|
514
testgap/remove.tst.ref
Normal file
514
testgap/remove.tst.ref
Normal file
@ -0,0 +1,514 @@
|
|||||||
|
<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>
|
30
testgap/run
Executable file
30
testgap/run
Executable file
@ -0,0 +1,30 @@
|
|||||||
|
#! /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;
|
||||||
|
|
@ -302,6 +302,11 @@ struct connection* udp_c2s_forward(int sockfd, struct loop_info* fd_info)
|
|||||||
cnx->addrlen = addrlen;
|
cnx->addrlen = addrlen;
|
||||||
cnx->local_endpoint = sockfd;
|
cnx->local_endpoint = sockfd;
|
||||||
|
|
||||||
|
if (inc_proto_connections(cnx)) {
|
||||||
|
tidy_connection(cnx, fd_info);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
res = new_source(fd_info->hash_sources, cnx);
|
res = new_source(fd_info->hash_sources, cnx);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
print_message(msg_connections_error, "Out of hash space for new incoming UDP connection -- increase udp_max_connections");
|
print_message(msg_connections_error, "Out of hash space for new incoming UDP connection -- increase udp_max_connections");
|
||||||
|
Loading…
x
Reference in New Issue
Block a user