Change *ip-log* to *log-ip* in docs to reflect the actual settings.
---
I have a special use case where I need to have support for the tcp proxy
protocol. I've added support for it and figure that I could send in a
patch for those who might also have a use case for this feature.
In this patch, before the tls handshake, the server will check for a
proxy protocol header. If it is found, then the remote_addr will be
overridden with the found source address. If no header is found, then no
changes are made to the connection.
I also noticed that the docs have the setting `log-ip` misspelled as
`ip-log`, so that has been fixed as well. Also added -x option to col in
render-docs so tables look nice in any editor.
P.S.
This is the first time I have worked with patch emails, so please let me
know if there is anything that I have done wrong.
Cargo.lock | 67 ++++-
Cargo.toml | 1 +
doc/stargazer-ini.scd | 10 +-
doc/stargazer.1.txt | 40 +--
doc/stargazer.ini.5.txt | 542 ++++++++++++++++++++--------------------
scripts/render-docs | 4 +-
src/main.rs | 105 +++++++-
7 files changed, 460 insertions(+), 309 deletions(-)
diff --git a/Cargo.lock b/Cargo.lock
index de04070..a3a88b5 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -41,7 +41,7 @@ checksum = "7378575ff571966e99a744addeff0bff98b8ada0dedf1956d59e634db95eaac1"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
"synstructure",
]
@@ -53,7 +53,7 @@ checksum = "7b18050c2cd6fe86c3a76584ef5e0baf286d038cda203eb6223df2cc413565f7"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
]
[[package]]
@@ -271,6 +271,12 @@ dependencies = [
"serde",
]
+[[package]]
+name = "bytes"
+version = "1.6.1"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a12916984aab3fa6e39d655a33e09c0071eb36d6ab3aea5c2d78551f1df6d952"
+
[[package]]
name = "cc"
version = "1.0.96"
@@ -430,7 +436,7 @@ checksum = "487585f4d0c6655fe74905e2504d8ad6908e4db67f744eb140876906c2f3175d"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
]
[[package]]
@@ -442,6 +448,12 @@ dependencies = [
"const-random",
]
+[[package]]
+name = "doc-comment"
+version = "0.3.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fea41bba32d969b513997752735605054bc0dfa92b4c56bf1189f2e174be7a10"
+
[[package]]
name = "errno"
version = "0.3.8"
@@ -884,6 +896,16 @@ dependencies = [
"unicode-ident",
]
+[[package]]
+name = "proxy-protocol"
+version = "0.5.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "0e50c72c21c738f5c5f350cc33640aee30bf7cd20f9d9da20ed41bce2671d532"
+dependencies = [
+ "bytes",
+ "snafu",
+]
+
[[package]]
name = "quote"
version = "1.0.36"
@@ -1067,7 +1089,7 @@ checksum = "856f046b9400cee3c8c94ed572ecdb752444c24528c035cd35882aad6f492bcb"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
]
[[package]]
@@ -1121,6 +1143,27 @@ dependencies = [
"autocfg",
]
+[[package]]
+name = "snafu"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "eab12d3c261b2308b0d80c26fffb58d17eba81a4be97890101f416b478c79ca7"
+dependencies = [
+ "doc-comment",
+ "snafu-derive",
+]
+
+[[package]]
+name = "snafu-derive"
+version = "0.6.10"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1508efa03c362e23817f96cde18abed596a25219a8b2c66e8db33c03543d315b"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
[[package]]
name = "socket2"
version = "0.4.10"
@@ -1174,6 +1217,7 @@ dependencies = [
"mime_guess",
"once_cell",
"percent-encoding",
+ "proxy-protocol",
"rcgen",
"regex",
"rust-ini",
@@ -1194,6 +1238,17 @@ version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc"
+[[package]]
+name = "syn"
+version = "1.0.109"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "unicode-ident",
+]
+
[[package]]
name = "syn"
version = "2.0.60"
@@ -1213,7 +1268,7 @@ checksum = "c8af7666ab7b6390ab78131fb5b0fce11d6b7a6951602017c35fa82800708971"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
]
[[package]]
@@ -1233,7 +1288,7 @@ checksum = "d1cd413b5d558b4c5bf3680e324a6fa5014e7b7c067a51e69dbdf47eb7148b66"
dependencies = [
"proc-macro2",
"quote",
- "syn",
+ "syn 2.0.60",
]
[[package]]
diff --git a/Cargo.toml b/Cargo.toml
index 22779c3..8aeeb73 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -53,6 +53,7 @@ mime_guess = "2.0.4"
socket2 = "0.5.7"
percent-encoding = "2.3.1"
uriparse = "0.6"
+proxy-protocol = "0.5.0"
anyhow = "1.0.82"
once_cell = "1.19.0"
diff --git a/doc/stargazer-ini.scd b/doc/stargazer-ini.scd
index f08b003..7a73de9 100644
--- a/doc/stargazer-ini.scd
+++ b/doc/stargazer-ini.scd
@@ -57,16 +57,16 @@ that *stargazer* will server requests to. At least one route must be specified.
Whether or not to log connections to stdout. Disabling this may increase
performance. On by default. Always on if the debug cli flag is on.
-*ip-log*
+*log-ip*
Log client IP addresses in the connection log. Mutually exclusive with
- *ip-log-partial*. Off by default.
+ *log-ip-partial*. Off by default.
-*ip-log-partial*
+*log-ip-partial*
Log partial client IP addresses in the connection log. For IPv4 addresses
only the first 2 octets are logged, the rest are zeroed. For IPv6 addresses
only the first 3 16bit segments are logged, the rest are zeroed. May be
- preferable to *ip-log* to help maintain user privacy. Mutually exclusive
- with *ip-log-partial*. Off by default.
+ preferable to *log-ip* to help maintain user privacy. Mutually exclusive
+ with *log-ip-partial*. Off by default.
*request-timeout*
Number of seconds to wait for the client to send a complete request. If
diff --git a/doc/stargazer.1.txt b/doc/stargazer.1.txt
index d0003ba..37e7877 100644
--- a/doc/stargazer.1.txt
+++ b/doc/stargazer.1.txt
@@ -1,4 +1,4 @@
-stargazer(1) General Commands Manual stargazer(1)
+stargazer(1) General Commands Manual stargazer(1)
NAME
stargazer - a gemini server
@@ -8,29 +8,29 @@ SYNOPSIS
ARGS
path
- Specifies an alternate path to read the config file from.
+ Specifies an alternate path to read the config file from.
OPTIONS
-D --debug
- Turn on debug logging. This logs a lot more information
- about the servers operation which is useful for debugging
- problems. This is more verbose then is likely desired for
- normal operation.
+ Turn on debug logging. This logs a lot more information
+ about the servers operation which is useful for debugging
+ problems. This is more verbose then is likely desired for
+ normal operation.
-d --dev
- Start the server in dev mode. Server will server files from
- the current directory over ‘localhost:1965‘. This overrides
- the config file and the -C option.
+ Start the server in dev mode. Server will server files from
+ the current directory over `localhost:1965`. This overrides
+ the config file and the -C option.
--check-config
- Check for config errors and exit.
+ Check for config errors and exit.
-V --version
- Print program version and exit.
+ Print program version and exit.
-h --help
- Print command line argument help.
+ Print command line argument help.
LOGGING
- Server errors and other debugging info is printed to stderr in
- an unspecified format. Client request logging is printed to
- stdout, with each of the following fields in order, separated
+ Server errors and other debugging info is printed to stderr in
+ an unspecified format. Client request logging is printed to
+ stdout, with each of the following fields in order, separated
by a tab character:
• Service time in RFC 3339 format
@@ -45,9 +45,9 @@ SEE ALSO
stargazer.ini(5) for configuration instructions.
AUTHORS
- Maintained by Sashanoraa <sasha@noraa.gay>. Up-to-date sources
- can be found at https://sr.ht/˜zethra/stargazer/ and
- bugs/patches can be submitted by email to
- ˜zethra/stargazer@lists.sr.ht.
+ Maintained by Sashanoraa <sasha@noraa.gay>. Up-to-date sources
+ can be found at https://sr.ht/~zethra/stargazer/ and
+ bugs/patches can be submitted by email to
+ ~zethra/stargazer@lists.sr.ht.
- 1980-01-01 stargazer(1)
+ 2024-07-29 stargazer(1)
diff --git a/doc/stargazer.ini.5.txt b/doc/stargazer.ini.5.txt
index f3bb559..05d25fc 100644
--- a/doc/stargazer.ini.5.txt
+++ b/doc/stargazer.ini.5.txt
@@ -1,303 +1,304 @@
-stargazer.ini(5) File Formats Manual stargazer.ini(5)
+stargazer.ini(5) File Formats Manual stargazer.ini(5)
NAME
stargazer.ini - configuration file for stargazer(1)
EXAMPLE CONFIG
- listen = 0.0.0.0
+ listen = 0.0.0.0
- [:tls]
- store = /var/lib/gemini/certs
- organiztion = example org
+ [:tls]
+ store = /var/lib/gemini/certs
+ organiztion = example org
- [example.com]
- root = /srv/gemini/example.com
+ [example.com]
+ root = /srv/gemini/example.com
- [example.com˜(.*).cgi(.*)]
- root = /srv/gemini/example.com/cgi-bin
- cgi = on
+ [example.com~(.*).cgi(.*)]
+ root = /srv/gemini/example.com/cgi-bin
+ cgi = on
- An default config file should also be installed at
+ An default config file should also be installed at
/etc/stargazer.ini
SYNTAX
- stargazer.ini is an INI file. Each line is either a key/value
- pair, or a section heading. Key/value pairs are specified as
+ stargazer.ini is an INI file. Each line is either a key/value
+ pair, or a section heading. Key/value pairs are specified as
key=value, and sections as [section]. Extra white space in gen‐
- erally ignored. Boolean values can be written as true/false,
+ erally ignored. Boolean values can be written as true/false,
on/off, yes/no, and are case insensitive.
CONFIGURATION KEYS
- The meaning of the key depends on the section. Anonymous keys
- (prior to the first [section] directive) are used to specify
- parameters for the daemon itself. Sections whose name is pre‐
- fixed with ":", e.g. [:tls], are sub-categories of the daemon
- configuration. Otherwise, section names refer to the hostnames
+ The meaning of the key depends on the section. Anonymous keys
+ (prior to the first [section] directive) are used to specify
+ parameters for the daemon itself. Sections whose name is pre‐
+ fixed with ":", e.g. [:tls], are sub-categories of the daemon
+ configuration. Otherwise, section names refer to the hostnames
of domains serviced by the stargazer daemon. Each of these sec‐
- tions is a route that stargazer will server requests to. At
+ tions is a route that stargazer will server requests to. At
least one route must be specified.
ANONYMOUS KEYS
listen
- A space-separated list of addresses that the daemon shall
- bind to. Each address shall take the format address:port.
- If :port is omitted, 1965 (the default Gemini port) is pre‐
- sumed. To specify an IPv6 address, enclose it in [], e.g.
- [::]. Note that IPv6 listener always have IPV6_V6ONLY set,
- so they will only listen on the IPv6 interface and not also
- IPv4. If you wish to listen on both, specify both.
- Stargazer supports listening on multiple interfaces/ports
- but does not support serving different content on different
- interfaces/ports. It does support serving different content
- on different domains and paths.
+ A space-separated list of addresses that the daemon shall
+ bind to. Each address shall take the format address:port.
+ If :port is omitted, 1965 (the default Gemini port) is pre‐
+ sumed. To specify an IPv6 address, enclose it in [], e.g.
+ [::]. Note that IPv6 listener always have IPV6_V6ONLY set,
+ so they will only listen on the IPv6 interface and not also
+ IPv4. If you wish to listen on both, specify both.
+ Stargazer supports listening on multiple interfaces/ports
+ but does not support serving different content on different
+ interfaces/ports. It does support serving different content
+ on different domains and paths.
connection-logging
- Whether or not to log connections to stdout. Disabling this
- may increase performance. On by default. Always on if the
- debug cli flag is on.
-
- ip-log
- Log client IP addresses in the connection log. Mutually ex‐
- clusive with ip-log-partial. Off by default.
-
- ip-log-partial
- Log partial client IP addresses in the connection log. For
- IPv4 addresses only the first 2 octets are logged, the rest
- are zeroed. For IPv6 addresses only the first 3 16bit seg‐
- ments are logged, the rest are zeroed. May be preferable to
- ip-log to help maintain user privacy. Mutually exclusive
- with ip-log-partial. Off by default.
+ Whether or not to log connections to stdout. Disabling this
+ may increase performance. On by default. Always on if the
+ debug cli flag is on.
+
+ log-ip
+ Log client IP addresses in the connection log. Mutually ex‐
+ clusive with log-ip-partial. Off by default.
+
+ log-ip-partial
+ Log partial client IP addresses in the connection log. For
+ IPv4 addresses only the first 2 octets are logged, the rest
+ are zeroed. For IPv6 addresses only the first 3 16bit seg‐
+ ments are logged, the rest are zeroed. May be preferable to
+ log-ip to help maintain user privacy. Mutually exclusive
+ with log-ip-partial. Off by default.
request-timeout
- Number of seconds to wait for the client to send a complete
- request. If the timeout is exceeded the timeout, stargazer
- will send ‘59 Request timeout‘ and close the connection. 5
- seconds by default. Set to 0 to disable.
+ Number of seconds to wait for the client to send a complete
+ request. If the timeout is exceeded the timeout, stargazer
+ will send `59 Request timeout` and close the connection. 5
+ seconds by default. Set to 0 to disable.
response-timeout
- Number of seconds to wait for the client to send a complete
- request and for stargazer to finish sending the response.
- If the timeout is exceeded the timeout, stargazer will send
- and close the connection. Disabled by default default.
- Warning, if this is set, large files and cgi scripts may be
- cut off before their response finishes.
+ Number of seconds to wait for the client to send a complete
+ request and for stargazer to finish sending the response.
+ If the timeout is exceeded the timeout, stargazer will send
+ and close the connection. Disabled by default default.
+ Warning, if this is set, large files and cgi scripts may be
+ cut off before their response finishes.
TLS KEYS
The following keys are accepted under the [:tls] section:
store
- Path to the certificate store on disk. This should be a
- persistent directory writable by the daemon. The daemon
- manages its own certificates - no user intervention is re‐
- quired, except in the case of moving the daemon to another
- host, in which case the certificate store must be copied to
- the new host.
+ Path to the certificate store on disk. This should be a
+ persistent directory writable by the daemon. The daemon
+ manages its own certificates - no user intervention is re‐
+ quired, except in the case of moving the daemon to another
+ host, in which case the certificate store must be copied to
+ the new host.
organization
- An optional key used during certificate generation. Fill
- this in with the name of the organization responsible for
- the host and it will be filled in as the X.509 /O name.
+ An optional key used during certificate generation. Fill
+ this in with the name of the organization responsible for
+ the host and it will be filled in as the X.509 /O name.
gen-certs
- Set to false to turn off automatic certificate generation.
+ Set to false to turn off automatic certificate generation.
regen-certs
- Set to false to turn off automatic regeneration of expired
- certificates.
+ Set to false to turn off automatic regeneration of expired
+ certificates.
cert-lifetime
- Set how long auto-generated certs last before expiring.
- Specified as a number followed by y for a number of years,
- m for a number of months (a month being 30 days), or d for
- a number days. Ex. 5y for 5 years or 30d for 30 days.
+ Set how long auto-generated certs last before expiring.
+ Specified as a number followed by y for a number of years,
+ m for a number of months (a month being 30 days), or d for
+ a number days. Ex. 5y for 5 years or 30d for 30 days.
ROUTING KEYS
- To configure stargazer to service requests, routing keys must
- be defined. The name of the configuration section is used to
+ To configure stargazer to service requests, routing keys must
+ be defined. The name of the configuration section is used to
determine what kinds of requests it configures.
- The format of the section name is the hostname to be serviced,
- followed by a token which defines the routing strategy, and a
- string whose format is specific to each routing strategy. The
- token and match string may be omitted (i.e. [hostname] alone),
+ The format of the section name is the hostname to be serviced,
+ followed by a token which defines the routing strategy, and a
+ string whose format is specific to each routing strategy. The
+ token and match string may be omitted (i.e. [hostname] alone),
which implies path routing against "/". A port may not be spec‐
ified along with the hostname. Stargazer does not support serv‐
ing different content on different ports.
- : Route by path prefix. The URL path is compared to
- "string/".
+ : Route by path prefix. The URL path is compared to
+ "string/".
= Exact match. The URL path must exactly match the string.
- ˜ Regular expression routing. The string is a Rust-compatible
- regular expression which is tested against the URL path.
- See the docs for the syntax section of the docs for the regex
- rust crate for a definition of the regular expression syntax
+ ~ Regular expression routing. The string is a Rust-compatible
+ regular expression which is tested against the URL path.
+
+ See the docs for the syntax section of the docs for the regex
+ rust crate for a definition of the regular expression syntax
and features:
https://docs.rs/regex/1.4.2/regex/#syntax
Some example section names and examples of matching paths:
- [example.org:/foo] /foo, /foo/bar, /foo/bar/baz
- [example.org=/foo.txt] /foo.txt
- [example.org˜/[a- /foo.png, /bar.webp
+ [example.org:/foo] /foo, /foo/bar, /foo/bar/baz
+ [example.org=/foo.txt] /foo.txt
+ [example.org~/[a- /foo.png, /bar.webp
z]+\.(png|jpg|webp)]
- Routes should be ordered from least to most specific. The
+ Routes should be ordered from least to most specific. The
matching algorithm attempts to match the URL against each route
in reverse order, and chooses the first route which matches.
- Within each routing section, the following keys are used to
+ Within each routing section, the following keys are used to
configure how stargazer will respond to matching requests:
root
- Configures the path on disk from which files shall be
- served for this host. The path component of the URL will be
- appended to this value to form the path to files on disk to
- serve.
+ Configures the path on disk from which files shall be
+ served for this host. The path component of the URL will be
+ appended to this value to form the path to files on disk to
+ serve.
- If example.org/foo/bar.txt is requested, and a route is
- configured for [example.org:/foo] with the root set to
- /srv/gemini, /srv/gemini/foo/bar.txt will be served.
+ If example.org/foo/bar.txt is requested, and a route is
+ configured for [example.org:/foo] with the root set to
+ /srv/gemini, /srv/gemini/foo/bar.txt will be served.
rewrite
- If regular expression routing is used, the rewrite direc‐
- tive may be used to rewrite the URL path component before
- proceeding. The URL will be set to the value of the rewrite
- expression. If \N appears in the rewrite value, where N is
- a number, that capture group will be substituted for \N. If
- \{name} appears, where name is a named capture group, it
- will be substituted. Capture group 0 refers to the entire
- matched path.
+ If regular expression routing is used, the rewrite direc‐
+ tive may be used to rewrite the URL path component before
+ proceeding. The URL will be set to the value of the rewrite
+ expression. If \N appears in the rewrite value, where N is
+ a number, that capture group will be substituted for \N. If
+ \{name} appears, where name is a named capture group, it
+ will be substituted. Capture group 0 refers to the entire
+ matched path.
- Example:
+ Example:
- [localhost˜ˆ/([a-zA-Z]+)\.(?P<extension>png|jpg)$]
- root=./root
- rewrite=/images/\1.\{extension}
+ [localhost~^/([a-zA-Z]+)\.(?P<extension>png|jpg)$]
+ root=./root
+ rewrite=/images/\1.\{extension}
- This will rewrite a request for /example.png to /images/ex‐
- ample.png. This directive will also modify the path of a
- redirect URL if used in a redirect route.
+ This will rewrite a request for /example.png to /images/ex‐
+ ample.png. This directive will also modify the path of a
+ redirect URL if used in a redirect route.
index
- Configures the name of the index file which shall be served
- in the event that a request for this host does not include
- the filename part. Defaults to "index.gmi".
+ Configures the name of the index file which shall be served
+ in the event that a request for this host does not include
+ the filename part. Defaults to "index.gmi".
auto-index
- "on" to enable the auto-index feature, which presents
- clients with a list of files in the requested directory
- when an index file cannot be found. Off by default. Only
- availible for static file routes.
+ "on" to enable the auto-index feature, which presents
+ clients with a list of files in the requested directory
+ when an index file cannot be found. Off by default. Only
+ availible for static file routes.
lang
- Set this value as the lang parameter for gemini files
- served under this route. The lang param will only be set
- for text/gemini responses. The Gemini Specification says
- that the lang parameter should contain a comma separated
- list of language identifier from RFC 4646. Stargazer will
- use the lang parameter as given in this config. It is up to
- the user to provid a valid list of languages. Currently,
- this parameter is only used when serving static files.
+ Set this value as the lang parameter for gemini files
+ served under this route. The lang param will only be set
+ for text/gemini responses. The Gemini Specification says
+ that the lang parameter should contain a comma separated
+ list of language identifier from RFC 4646. Stargazer will
+ use the lang parameter as given in this config. It is up to
+ the user to provid a valid list of languages. Currently,
+ this parameter is only used when serving static files.
charset
- Set this value as the charset parameter for text files
- served under this route. The lang param will only be set
- for text/* responses. If the lang parameter is also set,
- then lang will be set instead of charset for text/gemini
- responses. The Gemini Specification says that the charset
- parameter should be a character set specified in RFC 2046.
- Stargazer will use the charset parameter as given in this
- config. It is up to the user to provid a valid charset
- value. Currently, this parameter is only used when serving
- static files.
+ Set this value as the charset parameter for text files
+ served under this route. The lang param will only be set
+ for text/* responses. If the lang parameter is also set,
+ then lang will be set instead of charset for text/gemini
+ responses. The Gemini Specification says that the charset
+ parameter should be a character set specified in RFC 2046.
+ Stargazer will use the charset parameter as given in this
+ config. It is up to the user to provid a valid charset
+ value. Currently, this parameter is only used when serving
+ static files.
mime-override
- Override the MIME type of all files served under this route
- with the specified value. This parameter can only be used
- when serving static files. This can be used with an exact
- match route to override the MIME type for a single file.
+ Override the MIME type of all files served under this route
+ with the specified value. This parameter can only be used
+ when serving static files. This can be used with an exact
+ match route to override the MIME type for a single file.
redirect
- Send a redirect to this URI instead of serving other con‐
- tent. The URI exactly as written will be sent to the
- client. Mutually exclusive with most other settings.
+ Send a redirect to this URI instead of serving other con‐
+ tent. The URI exactly as written will be sent to the
+ client. Mutually exclusive with most other settings.
permanent
- Send a permanent redirect instead of a temporary redirect.
- Requires redirect to be set.
+ Send a permanent redirect instead of a temporary redirect.
+ Requires redirect to be set.
cgi
- "on" to enable CGI support. root must also be configured.
- See "CGI Support" for details. Mutually exclusive with
- auto-index.
+ "on" to enable CGI support. root must also be configured.
+ See "CGI Support" for details. Mutually exclusive with
+ auto-index.
cgi-user
- Run CGI process as this user and their primary group. Set
- to the name of the user. Otherwise process is run as same
- user as stargazer, which can be a security issue if the CGI
- process is untrusted (not that running untrusted CGI
- processes is a good idea to begin with). The user stargazer
- is run as must be able to setuid the child process to the
- user specified.
+ Run CGI process as this user and their primary group. Set
+ to the name of the user. Otherwise process is run as same
+ user as stargazer, which can be a security issue if the CGI
+ process is untrusted (not that running untrusted CGI pro‐
+ cesses is a good idea to begin with). The user stargazer is
+ run as must be able to setuid the child process to the user
+ specified.
scgi
- "on" to enable SCGI support. scg-address must also be
- set.See "SCI Support" for details. root, index, and auto-
- index not allowed when scgi is on.
+ "on" to enable SCGI support. scg-address must also be
+ set.See "SCI Support" for details. root, index, and auto-
+ index not allowed when scgi is on.
scgi-address
- The address of the SCGI server to connect to. If this is a
- valid file system path that exists, stargazer will connect
- to a Unix domain socket at that path to send requests. Oth‐
- erwise the address value will be treated as a socket ad‐
- dress and requests will be made over TCP.
+ The address of the SCGI server to connect to. If this is a
+ valid file system path that exists, stargazer will connect
+ to a Unix domain socket at that path to send requests. Oth‐
+ erwise the address value will be treated as a socket ad‐
+ dress and requests will be made over TCP.
cgi-timeout
- Maximum amount of time a CGI/SCGI process on this route is
- allowed to run. If the timeout is exceeded, stargazer will
- send a CGI error to the client and either kill the CGI
- process or close the SCGI connection. Values is a whole
- number of seconds. By default CGI processes have no timeout
- and stargazer will wait indefinitely for them to finish.
+ Maximum amount of time a CGI/SCGI process on this route is
+ allowed to run. If the timeout is exceeded, stargazer will
+ send a CGI error to the client and either kill the CGI
+ process or close the SCGI connection. Values is a whole
+ number of seconds. By default CGI processes have no timeout
+ and stargazer will wait indefinitely for them to finish.
cert-path
- Path to this certificate for this route, overrides the de‐
- fault store path. This is intended to be used for certs not
- managed by stargazer. As such stargazer will not attempt to
- generate or regenerate these certs. If this is set, key-
- path must also be set.
+ Path to this certificate for this route, overrides the de‐
+ fault store path. This is intended to be used for certs not
+ managed by stargazer. As such stargazer will not attempt to
+ generate or regenerate these certs. If this is set, key-
+ path must also be set.
key-path
- Path to the key that goes with the cert set by the cert-
- path. If this is set, cert-path must also be set.
+ Path to the key that goes with the cert set by the cert-
+ path. If this is set, cert-path must also be set.
client-cert
- Path to a client certificate that the client must use to
- access this route. Only one client certificate may be spec‐
- ified per route. Client certificate must be in the PEM for‐
- mat.
+ Path to a client certificate that the client must use to
+ access this route. Only one client certificate may be spec‐
+ ified per route. Client certificate must be in the PEM for‐
+ mat.
CGI Support
- stargazer supports a limited version of CGI, compatible with
+ stargazer supports a limited version of CGI, compatible with
the Jetforce server. It is not a faithful implementation of RFC
- 3875, but is sufficient for most of the needs of Gemini
+ 3875, but is sufficient for most of the needs of Gemini
servers.
- Set cgi=on for a route configuration to enable CGI for that
+ Set cgi=on for a route configuration to enable CGI for that
route and set root to the path where the CGI scripts are found.
- If a client requests a script, it will be executed, and must
- print a Gemini response (including status code and meta) to
+ If a client requests a script, it will be executed, and must
+ print a Gemini response (including status code and meta) to
stdout.
- If a CGI process exceeded the timeout set by cgi-timeout or if
- connection to client is lost and the CGI process is still run‐
- ning it will be killed. On *nix systems, the CGI process will
- receive a SIGTERM. If it is still running after 3 seconds it
+ If a CGI process exceeded the timeout set by cgi-timeout or if
+ connection to client is lost and the CGI process is still run‐
+ ning it will be killed. On *nix systems, the CGI process will
+ receive a SIGTERM. If it is still running after 3 seconds it
will receive a SIGKILL. On other systems (i.e. Windows) the CGI
- process will just be killed. If cgi-timeout is exceeded,
- stargazer will send a CGI error message to the gemini client
+ process will just be killed. If cgi-timeout is exceeded,
+ stargazer will send a CGI error message to the gemini client
before closing the connection.
When stargazer exits, any CGI processes that are currently run‐
@@ -305,104 +306,97 @@ CGI Support
The following environment variables will be set:
- ┌────────────────────┬──────────────────────┬─────────────────┐
- │ Variable │ Example │ Description │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ GATEWAY_INTERFACE │ CGI/1.1 │ CGI version │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ SERVER_PROTOCOL │ GEMINI │ The server pro‐ │
- │ │ │ tocol │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ SERVER_SOFTWARE │ stargazer/0.1.0 │ The stargazer │
- │ │ │ server name and │
- │ │ │ version │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ GEMINI_URL │ See [1] │ The URL re‐ │
- │ │ │ quested by the │
- │ │ │ client │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ SCRIPT_NAME │ /cgi-bin/foo.sh │ The portion of │
- │ │ │ the URL refer‐ │
- │ │ │ ring to the │
- │ │ │ script name. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ PATH_INFO │ /bar │ The remainder │
- │ │ │ of the path │
- │ │ │ following │
- │ │ │ SCRIPT_NAME. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ QUERY_STRING │ hello=world │ The query │
- │ │ │ string portion │
- │ │ │ of the URL. [3] │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ SERVER_NAME, │ example.org │ The server host │
- │ HOSTNAME │ │ name. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ SERVER_PORT │ 1965 │ The server port │
- │ │ │ number. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ REMOTE_HOST, RE‐ │ 10.10.0.2 │ The clients IP │
- │ MOTE_ADDR │ │ address. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ TLS_CLIENT_HASH │ See [2] │ A fingerprint │
- │ │ │ that can be │
- │ │ │ used to │
- │ │ │ uniquely iden‐ │
- │ │ │ tify the cert. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ TLS_CLIENT_NOT_BE‐ │ 2020-10-22T04:31:40Z │ The date the │
- │ FORE │ │ client's cert │
- │ │ │ is not valid │
- │ │ │ before. See │
- │ │ │ [4]. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ TLS_CLIENT_NOT_AF‐ │ 2021-10-22T04:31:59Z │ The date the │
- │ TER │ │ client's cert │
- │ │ │ is not valid │
- │ │ │ after. See [4]. │
- ├────────────────────┼──────────────────────┼─────────────────┤
- │ REMOTE_USER │ "My cert" │ The client │
- │ │ │ cert's issuer │
- │ │ │ field. │
- └────────────────────┴──────────────────────┴─────────────────┘
-
+ ┌───────────────────┬──────────────────────┬───────────────────┐
+ │Variable │ Example │ Description │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │GATEWAY_INTERFACE │ CGI/1.1 │ CGI version │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │SERVER_PROTOCOL │ GEMINI │ The server proto‐ │
+ │ │ │ col │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │SERVER_SOFTWARE │ stargazer/0.1.0 │ The stargazer │
+ │ │ │ server name and │
+ │ │ │ version │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │GEMINI_URL │ See [1] │ The URL requested │
+ │ │ │ by the client │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │SCRIPT_NAME │ /cgi-bin/foo.sh │ The portion of │
+ │ │ │ the URL referring │
+ │ │ │ to the script │
+ │ │ │ name. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │PATH_INFO │ /bar │ The remainder of │
+ │ │ │ the path follow‐ │
+ │ │ │ ing SCRIPT_NAME. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │QUERY_STRING │ hello=world │ The query string │
+ │ │ │ portion of the │
+ │ │ │ URL. [3] │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │SERVER_NAME, │ example.org │ The server host │
+ │HOSTNAME │ │ name. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │SERVER_PORT │ 1965 │ The server port │
+ │ │ │ number. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │REMOTE_HOST, RE‐ │ 10.10.0.2 │ The clients IP │
+ │MOTE_ADDR │ │ address. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │TLS_CLIENT_HASH │ See [2] │ A fingerprint │
+ │ │ │ that can be used │
+ │ │ │ to uniquely iden‐ │
+ │ │ │ tify the cert. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │TLS_CLIENT_NOT_BE‐ │ 2020-10-22T04:31:40Z │ The date the │
+ │FORE │ │ client's cert is │
+ │ │ │ not valid before. │
+ │ │ │ See [4]. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │TLS_CLIENT_NOT_AF‐ │ 2021-10-22T04:31:59Z │ The date the │
+ │TER │ │ client's cert is │
+ │ │ │ not valid after. │
+ │ │ │ See [4]. │
+ ├───────────────────┼──────────────────────┼───────────────────┤
+ │REMOTE_USER │ "My cert" │ The client cert's │
+ │ │ │ issuer field. │
+ └───────────────────┴──────────────────────┴───────────────────┘
[1]: gemini://example.org/cgi-bin/foo.sh/bar?hello=world
[2]: 1flC87yanv8KQ027TrvOOP/kA5yTWn3xLPJ+GxgaNB4=
- [3]: stargazer will attempt to percent decode the query string
- as UTF-8. If this fails the string will be provided as is, un‐
+ [3]: stargazer will attempt to percent decode the query string
+ as UTF-8. If this fails the string will be provided as is, un‐
decoded. [4]: Timestamps are rfc3339 complaint, exact format is
unspecified.
The exit status of the script is ignored.
SCGI Support
- stargazer has SCGI support similar to its CGI support. Set
+ stargazer has SCGI support similar to its CGI support. Set
scgi=on for a route configuration to enable SCGI for that route
and set scgi-address to the address of the SCGI server. The ad‐
- dress can either be a path to an Unix Domain Socket or the TCP
- Socket address. The headers included in the SCGI request match
+ dress can either be a path to an Unix Domain Socket or the TCP
+ Socket address. The headers included in the SCGI request match
the CGI parameters list above with a few exceptions.
If the SCGI server doesn't finish responding before cgi-timeout
is exceeded (assuming one is set) stargazer will close the con‐
- nection to the SCGI server and send a CGI error to the gemini
+ nection to the SCGI server and send a CGI error to the gemini
client.
- If the connection to the gemini client is lost stargazer will
+ If the connection to the gemini client is lost stargazer will
close the connection to the SCGI server.
New headers:
- ┌────────────────┬─────────┬──────────────────────────────────┐
- │ Variable │ Example │ Description │
- ├────────────────┼─────────┼──────────────────────────────────┤
- │ CONTENT_LENGTH │ 0 │ Length in bytes of the request │
- │ │ │ body. See [1]. │
- ├────────────────┼─────────┼──────────────────────────────────┤
- │ SCGI │ 1 │ SCGI Version │
- └────────────────┴─────────┴──────────────────────────────────┘
-
- [1]: Aways 0 since gemini doesn't have request bodies but in‐
+ ┌───────────────┬─────────┬────────────────────────────────────┐
+ │Variable │ Example │ Description │
+ ├───────────────┼─────────┼────────────────────────────────────┤
+ │CONTENT_LENGTH │ 0 │ Length in bytes of the request │
+ │ │ │ body. See [1]. │
+ ├───────────────┼─────────┼────────────────────────────────────┤
+ │SCGI │ 1 │ SCGI Version │
+ └───────────────┴─────────┴────────────────────────────────────┘
+ [1]: Aways 0 since gemini doesn't have request bodies but in‐
cluded as it's required by the SCGI protocol.
CGI header that are omitted from SCGI:
@@ -410,9 +404,9 @@ SCGI Support
• GATEWAY_INTERFACE
AUTHORS
- Maintained by Sashanoraa <sasha@noraa.gay>. Up-to-date sources
- can be found at https://sr.ht/˜zethra/stargazer/ and
- bugs/patches can be submitted by email to
- ˜zethra/stargazer@lists.sr.ht.
+ Maintained by Sashanoraa <sasha@noraa.gay>. Up-to-date sources
+ can be found at https://sr.ht/~zethra/stargazer/ and
+ bugs/patches can be submitted by email to
+ ~zethra/stargazer@lists.sr.ht.
- 1980-01-01 stargazer.ini(5)
+ 2024-07-29 stargazer.ini(5)
diff --git a/scripts/render-docs b/scripts/render-docs
index dd337fb..517ef38 100755
--- a/scripts/render-docs
+++ b/scripts/render-docs
@@ -1,4 +1,4 @@
#!/bin/sh
-scdoc < doc/stargazer.scd | MANWIDTH=72 man -l - | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | col -b > doc/stargazer.1.txt
-scdoc < doc/stargazer-ini.scd | MANWIDTH=72 man -l - | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | col -b > doc/stargazer.ini.5.txt
+scdoc < doc/stargazer.scd | MANWIDTH=72 man -l - | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | col -bx > doc/stargazer.1.txt
+scdoc < doc/stargazer-ini.scd | MANWIDTH=72 man -l - | sed -r "s/\x1B\[([0-9]{1,2}(;[0-9]{1,2})?)?[mGK]//g" | col -bx > doc/stargazer.ini.5.txt
diff --git a/src/main.rs b/src/main.rs
index b0fa9ba..6049cce 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -30,6 +30,7 @@ use async_executor::Executor;
use async_io::Timer;
use async_net::{SocketAddrV6, TcpListener, TcpStream};
use cgi::{serve_cgi, serve_scgi};
+use core::slice;
use futures_lite::*;
use futures_rustls::{server::TlsStream, TlsAcceptor};
use get_file::get_file;
@@ -234,14 +235,114 @@ async fn exit_on_sig() -> Result<()> {
Ok(future::pending::<()>().await)
}
+async fn parse_proxy_proto(
+ stream: &mut TcpStream,
+) -> anyhow::Result<Option<proxy_protocol::ProxyHeader>> {
+ // proxy-protocol doesn't support async streams, so in order to parse the
+ // proxy protocol, we need to pre-read the header before passing it in
+ // without reading into tls data.
+ //
+ // First, check if there is a proxy protocol header with the first 12 bytes.
+ // Second, read the whole proxy protocol header.
+ // Third, pass the raw data into proxy-protocol to get parsed.
+
+ let mut header = [0u8; 12];
+ let n = stream.peek(&mut header).await?;
+ let header = &header[..n];
+
+ if header.starts_with(b"PROXY ") {
+ // V1 - Read until \r\n
+ let mut buf = Vec::<u8>::with_capacity(n);
+ loop {
+ // There might be a better way than reading 1 byte at a time
+ let mut b = 0u8;
+ stream.read_exact(slice::from_mut(&mut b)).await?;
+ buf.push(b);
+ if b == b'\n' {
+ break;
+ }
+ }
+
+ let mut buf = buf.as_slice();
+
+ Ok(Some(proxy_protocol::parse(&mut buf)?))
+ } else if header.starts_with(&[
+ 0x0D, 0x0A, 0x0D, 0x0A, 0x00, 0x0D, 0x0A, 0x51, 0x55, 0x49, 0x54, 0x0A,
+ ]) {
+ // TODO this is untested. It should work, but I should make sure that
+ // the correct number of bytes are being read.
+
+ // V2 - Read header length bytes after the first 16 at [14,15]
+ let mut header = [0u8; 16];
+ stream.read_exact(&mut header).await?;
+ let len = u16::from_be_bytes([header[14], header[15]]);
+
+ let mut buf = vec![0u8; 16 + len as usize];
+ let buf_slice = buf.as_mut_slice();
+ header
+ .into_iter()
+ .enumerate()
+ .for_each(|(i, c)| buf_slice[i] = c);
+ stream.read_exact(&mut buf_slice[16..]).await?;
+ let mut buf = buf.as_slice();
+
+ Ok(Some(proxy_protocol::parse(&mut buf)?))
+ } else {
+ // There is no proxy protocol header, so do nothing
+ Ok(None)
+ }
+}
+
// This is a separate function for ease of error handling
async fn start_task(
- stream: TcpStream,
+ mut stream: TcpStream,
acceptor: TlsAcceptor,
- remote_addr: SocketAddr,
+ mut remote_addr: SocketAddr,
server_port: u16,
) {
use anyhow::Context;
+
+ // Parse the proxy protocol header. If there is one, then replace the
+ // remote_addr with the proxied source addr
+ match parse_proxy_proto(&mut stream)
+ .await
+ .context("Error reading proxy protocol")
+ {
+ Ok(Some(proxy_protocol::ProxyHeader::Version1 { addresses })) => {
+ match addresses {
+ proxy_protocol::version1::ProxyAddresses::Unknown => {}
+ proxy_protocol::version1::ProxyAddresses::Ipv4 {
+ source,
+ destination: _,
+ } => remote_addr = SocketAddr::V4(source),
+ proxy_protocol::version1::ProxyAddresses::Ipv6 {
+ source,
+ destination: _,
+ } => remote_addr = SocketAddr::V6(source),
+ }
+ }
+ Ok(Some(proxy_protocol::ProxyHeader::Version2 {
+ command: _,
+ transport_protocol: _,
+ addresses,
+ })) => match addresses {
+ proxy_protocol::version2::ProxyAddresses::Ipv4 {
+ source,
+ destination: _,
+ } => remote_addr = SocketAddr::V4(source),
+ proxy_protocol::version2::ProxyAddresses::Ipv6 {
+ source,
+ destination: _,
+ } => remote_addr = SocketAddr::V6(source),
+ _ => {}
+ },
+ Ok(_) => {}
+ Err(e) => {
+ debug!("{:#}", e);
+ return;
+ }
+ };
+
// Accept tsl connection
match acceptor
.accept(stream)
--
2.39.3 (Apple Git-146)