diff --git a/README.md b/README.md index e9a91aa..f07c0f9 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # A simplistic and secure Gemini server **Vger** is a gemini server supporting chroot, virtualhosts, default -language choice and MIME types detection. +language choice, redirections and MIME types detection. **Vger** design is relying on inetd and a daemon to take care of TLS. The idea is to delegate TLS and network to daemons which @@ -91,3 +91,5 @@ On OpenBSD, enable inetd and relayd and start them: # rcctl enable relayd inetd # rcctl start relayd inetd ``` + +Vger will serve files named `index.gmi` if no explicite filename is given. diff --git a/main.c b/main.c index 8633f06..43d31eb 100644 --- a/main.c +++ b/main.c @@ -21,7 +21,8 @@ void display_file(const char *, const char *); -void status (const int, const char *, const char *); +void status(const int, const char *, const char *); +void status_redirect(const int code, const char *url); void drop_privileges(const char *, const char *); void eunveil(const char *path, const char *permissions); size_t estrlcat(char *dst, const char *src, size_t dstsize); @@ -127,6 +128,13 @@ status(const int code, const char *file_mime, const char *lang) code, file_mime, lang); } +void +status_redirect(const int code, const char *url) +{ + printf("%i %s\r\n", + code, url); +} + void display_file(const char *path, const char *lang) { @@ -135,19 +143,28 @@ display_file(const char *path, const char *lang) ssize_t nread = 0; char *buffer[BUFSIZ]; const char *file_mime; + char target[FILENAME_MAX] = ""; - /* this is to check if path is a directory */ - if (stat(path, &sb) == -1) + /* this is to check if path exists and obtain metadata later */ + if (stat(path, &sb) == -1) { + + /* check if path is a symbolic link + * if so, redirect using its target */ + if (lstat(path, &sb) != -1 && S_ISLNK(sb.st_mode) == 1) + goto redirect; + else + goto err; + } + + + /* check if directory */ + if (S_ISDIR(sb.st_mode) == 1) goto err; /* open the file requested */ if ((fd = fopen(path, "r")) == NULL) goto err; - /* check if directory */ - if (S_ISDIR(sb.st_mode) == 1) - goto err; - file_mime = get_file_mime(path); status(20, file_mime, lang); @@ -165,8 +182,23 @@ err: syslog(LOG_DAEMON, "path invalid %s", path); goto closefd; +redirect: + /* read symbolic link target to redirect */ + if (readlink(path, target, FILENAME_MAX) == -1) { + int errnum = errno; + fprintf(stderr, "Value of errno: %d\n", errno); + perror("Error printed by perror"); + fprintf(stderr, "Error opening file: %s\n", strerror( errnum )); + goto err; + } + + status_redirect(39, target); + syslog(LOG_DAEMON, "redirection from %s to %s", path, target); + closefd: - fclose(fd); + if (S_ISREG(sb.st_mode) == 1) { + fclose(fd); + } } int diff --git a/tests/test.sh b/tests/test.sh index 7f93a46..3034054 100644 --- a/tests/test.sh +++ b/tests/test.sh @@ -34,6 +34,10 @@ if ! [ $OUT = "e663f17730d5ddc24010c14a238e1e78" ] ; then echo "error" ; exit 1 OUT=$(printf "gemini://perso.pw/foobar.unknown\r\n" | ../vger -d var/gemini/ -l fr | tee /dev/stderr | $MD5) if ! [ $OUT = "649a2e224632b679fd7599eafb13c001" ] ; then echo "error" ; exit 1 ; fi +# redirect file +OUT=$(printf "gemini://perso.pw/old_location\r\n" | ../vger -d var/gemini/ | tee /dev/stderr | $MD5) +if ! [ $OUT = "28262311ea814e6a481fa365894cfc3f" ] ; then echo "error" ; exit 1 ; fi + # file from local directory using virtualhosts OUT=$(printf "gemini://perso.pw/index.gmi\r\n" | ../vger -v -d var/gemini/ | tee /dev/stderr | $MD5) if ! [ $OUT = "0d36a423a4e8be813fda4022f08b3844" ] ; then echo "error" ; exit 1 ; fi diff --git a/vger.8 b/vger.8 index 6c2e33a..9265fa0 100644 --- a/vger.8 +++ b/vger.8 @@ -20,6 +20,9 @@ behind a relay daemon offering TLS capabilities like If an incoming gemini query doesn't explicitly request a file, .Nm will serves a default "index.gmi" file if present. +.Pp +It is possible to create redirections by creating a symbolic link +containing the new file location. .Sh OPTIONS .Bl -tag -width Ds .It Op Fl l Ar lang