# Replace placeholders like %%IP%% or %%BOFH%%.
info = replace_placeholders(info, client)
- print(info)
+ return info
class FingerHandler(socketserver.StreamRequestHandler):
import os
import sys
+import glob
+
+#
+# Add the Git project root to Python's sys.path,
+# and make it the current working directory.
+#
+# When invoked by inetd, this is required for all
+# code find below these lines.
+#
BBS = os.path.abspath(os.path.join(os.path.dirname(__file__), ".."))
sys.path.insert(0, BBS)
os.chdir(BBS)
+
+# Now we can import mfingerd
import bbs.mfingerd
+
+#
try:
username = sys.stdin.readline().strip()
except UnicodeDecodeError:
print("???")
sys.exit(0)
+#
+# inetd passes the client IP to us using an environment
+# variable
+#
remote_ip = os.getenv("TCPREMOTEIP", None)
# }}}"""
-bbs.mfingerd.fingerinfo(username, remote_ip)
+#
+# rfc/ - Serve some selected RFCs in plain text format
+#
+RFC_PATH = "/opt/bbs/finger-smallweb/rfcs"
+HOSTNAME = "giesskanne.flachbaum.de"
+
+def get_rfc_filenames_sorted(rfc_path: str, glob_expression = "rfc*.txt"):
+ rfc_files = glob.glob(os.path.join(rfc_path, glob_expression))
+ rfc_files = sorted(
+ rfc_files,
+ key = lambda x: int(
+ x.split("/")[-1].replace("rfc","").replace(".txt","")
+ )
+ )
+ return rfc_files
+
+
+if username.split("/")[0] == "rfc":
+ rfc_id = username.rstrip("/").split("/")
+ if len(rfc_id) > 1:
+ rfc_id = rfc_id[1]
+ else:
+ rfc_id = "-1"
+
+ try:
+ if str(int(rfc_id)) != rfc_id:
+ print("rfc :: Invalid RFC ID!")
+ sys.exit(0)
+ except:
+ print("EXCEPTION")
+ sys.exit(0)
+
+ if int(rfc_id) >= 1:
+ rfc_file = os.path.join(
+ RFC_PATH,
+ "rfc" + str(int(rfc_id)) + ".txt"
+ )
+
+ if not os.path.exists(rfc_file):
+ print("RFC " + rfc_id + " now available yet on this service.")
+ sys.exit(0)
+
+ with open(rfc_file) as rfc:
+ contents = ""
+ for l in rfc.readlines():
+ l = l.rstrip("\n").replace("\x0c", "\n\n\n\n\n")
+ contents += l + "\n"
+
+ else:
+ contents = ""
+ contents += "List of RFCs viewable on this server:\n"
+ contents += "\n"
+
+ for rfc_file in get_rfc_filenames_sorted(RFC_PATH):
+ rfc_id = rfc_file.split("/")[-1].replace("rfc","").replace(".txt","")
+ contents += "finger://"
+ contents += HOSTNAME
+ contents += "/rfc/" + str(rfc_id)
+ contents += "\n"
+
+ contents += "\n\n"
+ contents += "More documents might be available in the future.\n"
+
+ print(contents)
+
+ sys.exit(0)
+
+
+#
+# qotd.py - Serve my QOTD client over finger://
+#
+if username == "qotd.py":
+ script_filename = "bin/qotd.py"
+ try:
+ with open(script_filename, "r") as f:
+ content = f.read()
+
+ except FileNotFoundError:
+ print("Server Error: File not found.")
+ sys.exit()
+
+ except PermissionError:
+ print("Server Error: Premission denied.")
+ sys.exit()
+
+ print(content)
+ sys.exit()
+
+
+#
+# Display fingerinfo from database
+#
+print(bbs.mfingerd.fingerinfo(username, remote_ip))
+
--- /dev/null
+#!/usr/bin/env python3
+
+__doc__ = """A basic QOTD client.
+
+Use socket.socket to get a qoute of the day
+from a remote server.
+
+Uses my own QOTD server by default, but you
+can set your own hostname and port using
+environment variables:
+
+- $QOTD_HOST
+ - Defaults to "giesskanne.flachbaum.de"
+- $QOTD_PORT
+ - Defaults to 17
+"""
+
+import os
+import sys
+import socket
+
+
+QOTD_HOST = "giesskanne.flachbaum.de"
+QOTD_PORT = 17
+
+
+def get_qotd(
+ remote_addr: tuple[str, int] = (QOTD_HOST, QOTD_PORT),
+ buffer_size: int = 64,
+ read_limit: int | None = 2048
+ ) -> str:
+ """Retrieve a qoute from a QOTD server.
+
+ Args:
+ remote_addr (tuple[str, int]): Remote host and port number.
+
+ Returns:
+ str: The quote recieved from `remote_addr`
+
+ """
+ s = socket.socket(
+ socket.AF_INET,
+ socket.SOCK_STREAM
+ )
+ s.connect(remote_addr)
+
+ qotd = ""
+ while True:
+ data = s.recv(buffer_size)
+ if not data or data is None:
+ break
+ qotd += data.decode("UTF-8")
+ s.close()
+
+ return qotd
+
+
+def main():
+ # Default host and port from environment variables, falls back to
+ # `QOTD_HOST` and `QOTD_PORT` defined above.
+ qotd_remote_server = (
+ os.getenv("QOTD_HOST", QOTD_HOST),
+ int(os.getenv("QOTD_PORT", QOTD_PORT))
+ )
+ try:
+ print(get_qotd(qotd_remote_server))
+
+ except ConnectionRefusedError:
+ _remote = qotd_remote_server[0] + ":" + str(qotd_remote_server[1])
+ print(f"{os.path.basename(__file__)}: Error: Connection refused "
+ f"to {_remote}", file=sys.stderr)
+ return 1
+
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
--- /dev/null
+# Host a finger:// smallweb page using bbs.mfingerd
+
+
--- /dev/null
+
+
+
+
+
+
+Network Working Group D. Waitzman
+Request for Comments: 1149 BBN STC
+ 1 April 1990
+
+
+ A Standard for the Transmission of IP Datagrams on Avian Carriers
+
+Status of this Memo
+
+ This memo describes an experimental method for the encapsulation of
+ IP datagrams in avian carriers. This specification is primarily
+ useful in Metropolitan Area Networks. This is an experimental, not
+ recommended standard. Distribution of this memo is unlimited.
+
+Overview and Rational
+
+ Avian carriers can provide high delay, low throughput, and low
+ altitude service. The connection topology is limited to a single
+ point-to-point path for each carrier, used with standard carriers,
+ but many carriers can be used without significant interference with
+ each other, outside of early spring. This is because of the 3D ether
+ space available to the carriers, in contrast to the 1D ether used by
+ IEEE802.3. The carriers have an intrinsic collision avoidance
+ system, which increases availability. Unlike some network
+ technologies, such as packet radio, communication is not limited to
+ line-of-sight distance. Connection oriented service is available in
+ some cities, usually based upon a central hub topology.
+
+Frame Format
+
+ The IP datagram is printed, on a small scroll of paper, in
+ hexadecimal, with each octet separated by whitestuff and blackstuff.
+ The scroll of paper is wrapped around one leg of the avian carrier.
+ A band of duct tape is used to secure the datagram's edges. The
+ bandwidth is limited to the leg length. The MTU is variable, and
+ paradoxically, generally increases with increased carrier age. A
+ typical MTU is 256 milligrams. Some datagram padding may be needed.
+
+ Upon receipt, the duct tape is removed and the paper copy of the
+ datagram is optically scanned into a electronically transmittable
+ form.
+
+Discussion
+
+ Multiple types of service can be provided with a prioritized pecking
+ order. An additional property is built-in worm detection and
+ eradication. Because IP only guarantees best effort delivery, loss
+ of a carrier can be tolerated. With time, the carriers are self-
+
+
+
+Waitzman [Page 1]
+\f
+RFC 1149 IP Datagrams on Avian Carriers 1 April 1990
+
+
+ regenerating. While broadcasting is not specified, storms can cause
+ data loss. There is persistent delivery retry, until the carrier
+ drops. Audit trails are automatically generated, and can often be
+ found on logs and cable trays.
+
+Security Considerations
+
+ Security is not generally a problem in normal operation, but special
+ measures must be taken (such as data encryption) when avian carriers
+ are used in a tactical environment.
+
+Author's Address
+
+ David Waitzman
+ BBN Systems and Technologies Corporation
+ BBN Labs Division
+ 10 Moulton Street
+ Cambridge, MA 02238
+
+ Phone: (617) 873-4323
+
+ EMail: dwaitzman@BBN.COM
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+Waitzman [Page 2]
+\f
\ No newline at end of file