litchralee

u/litchralee@sh.itjust.works
202 posts · 1.8k comments

Recent posts

Recent comments

IMO, Leetcode and other programming exercises are a simulacrum for assessing aptitude. The exact exercise is not the point -- though many managers might think otherwise -- but rather is the process: can a candidate methodically approach a challenge with sufficient rigor as becoming of an engineer?

I've written before about what I look for when conducting interviews, in the context of embedded software engineers. In that realm, I'm usually probing for prior experience with computer architecture in general, not necessarily in the particular framework that the job will deal in. I want to see transferrable skills, because it's kinda rare to actually find perfect candidates that already meet our final requirements. So instead, I expect candidates to be quick studies, the sort of people that can draw analogies and get an approximate answer. Everything else can reasonably be looked up in man pages and web searches.

But this might just be specific to embedded, where we do actually care about the nitty gritty compiler and assembly details, when there's only 512 KB of RAM. And to be clear, a candidate that knows bit tricks will likely do well, but if that's the only tool in their toolbox and they don't or can't understand why writing maintainable, mostly-portable code is important, then that could be a problem. In this realm, programming exercises are still a view into a mindset. Other CS fields may vary.

My cursory understanding of the BlueSky/AT approach is that posts are not anchored to the identity, but to a value akin to a DOI like how research papers are referenced. And in that way, something like a BlueSky post can be hosted as a standalone document, whose provenance is through a linkage to the user identifier maintained by the separate identity infrastructure. I believe this is why hyperlinks to BlueSky posts do not -- and cannot -- include the author's handle, whereas Fediverse links often do (but aren't required to).

So yes, the server that hosts content is separate from the identity server. But the part I still don't see is how to update a document's associated identity if a user changes to a different identity server. It is indeed a separation of concern -- which is very healthy and I do follow developments in the AT space which could be used to drive improvements in the ActivityPub world -- but the same scenario is still doomed: if the identity server skips town suddenly, can former users restart with a new identity and reassociate to their prior documents? How can this be done securely?

But my original point remains: the challenge is nontrivial and no one should underestimate the complexity, whether it's in the ActivityPub or AT model. This federation thing is hard.

I'll take a stab at answering the titular question, which also requires answering the related question: "what really is federation?"

In my conception, federation makes the most sense if we rewind to a (almost) bygone era, in the early 21st Century where every specific communities hosted their own web forums, before a time when Facebook groups or Discord "servers" were mainstream. Of those, I think the ones which endured the longest are those related to automobile enthusiasts, usually about a specific model (eg Corvette), in order to exchange tips and servicing info.

What federation solves is the challenge of maintaining a different login -- aka identity -- on each web forum that someone frequents. Back then, it was a separate username and password for the car enthusiast forum, another for the regional gossip forum, yet another for the anarchist forum. And despite that, the underlying credential was usually the same: an email address.

So instead of managing an identity at each different web forum, federation is the idea of having a single identity that can travel to different domains. The open model of email is instructive, because sending an email necessarily interacts with the destination domain, which is usually not the same as one's own. Phrased another way, the postal system was the first federated communication system, where different states honored the single identity and allowed free* passage. One might compare this to one of the EU's four freedoms, the free movement of labor: a user may do work (ie write a post) on any instance in a federation, on equal standing whether they're local or not.

In the modern context in the 2020s, such a freedom is in stark contrast to the commercial alternatives: using a Facebook, Google, or Apple login to access any particular website more often than not puts oneself on a different (ie lower) standing than if they logged in with an untethered account. The usual problem is that such a common identity is tracked and sold to marketers, which explains why so many sites use these single sign-ons as a default, and only begrudgingly support "old school" account creation for that specific site.

And worse so, if Google decides you are unworthy of a Google Account, then you simultaneously lose your online identity and any semblance of access to those services which you were using. Federation solves the latter, because if your federated identity is banned from your home instance, the freedoms of federation means you can create an identity elsewhere and use that to access Fediverse services, apart from the one which originally had reason to ban you.

Nobody can deny you access to every instance, and that's what makes it powerful: there is no centralized arbiter for the network. Sure, this means there will be some very ugly parts of the Internet that get to exist and possibly interact with the rest of the decent web. But just like with the majors, the challenge of moderation still remains albeit different. Some segments are wholly an island unto themselves (eg certain right wing circles that also use Fediverse software) because nobody else will federate to their instance.

Going back to the original question, the central issue is that while the network is decentralized, a single identity necessarily is centralized on their home instance. And there's no real way around this, because having a single identity means it must be unambiguous to reference: if I @ you, there must be exactly one possible identity, or else everything breaks down. So the notion of "transferring" an identity would become a horrible routing kludge like how "portable telephone numbers" are implemented in the Telco space: the original exchange has to remain alive to forward to the new exchange. And that's basically unworkable in the decentralized Fediverse in general, because instances can come and go.

There is no way to guarantee that one's home instance stays alive forever, which limits the identity's lifetime. If we had it leave a note that you've moved, how to we retrieve the note after the original instance is down? Telco could do it because there's a centralized listing of all valid exchanges, but there is no such thing on the Fediverse. It's the sort of thing that requires a "dying message" ledger, and it's hard to imagine how something like DNS could solve that knowledge challenge issue.

At bottom, creating identity resilience is hard and we don't have it yet. But that's because federation was always going to be difficult, and in spite of that, we seek out the world we want, not compromise with the world we were given.

That looks like a BS 1363 power strip? It seems fine to me: I see a circuit breaker, an MOV, and each socket is switched on the live (brown, in IEC color convention) wire.

Furthermore, I don’t believe I want to be a landlord. Ain’t it too stressful?

If an investment would keep you awake at night, it's the wrong investment for you. From the Bogleheads investment philosophy (mostly USA centric, but easily tweaked for non-USA):

Aim to select an asset allocation that lets you sleep at night, and avoid the destructive urge to sell out in a panic the next time the market plummets, then having to worry over when is the time to get back in. This leads to selling low and buying high, the exact opposite of prudent investing.

As you said, your time horizon is at least 25 years. Would you want to be a landlord (even one that just outsources everything to a property management company) for nearly three decades?

I will offer two anecdotes from colleagues of mine that pursued rental property. The first colleague came from a family of real estate agents, and basically every branch of his extended family already had rental properties. He now has six rental properties and benefitted from the extensive "knowledge capital" within his family on how to do rentals properly. He's also good with DIY and carefully selected long-term tenants that reliably pay rent, so he doesn't have to raise rent often, which keeps turnover low. It was clear he would be fine as a landlord, as a part of his diversified portfolio.

My second colleague became a landlord because he got married and moved to a different area to start a family, meaning his original home could be rented out. He wasn't too far though, so he took care of the property maintenance himself. As it happened, when he had twins, there wasn't much time left to deal with the rental, and in the end it was easier to just sell it and focus on his family. He made positive money from the sale, but the nature of holding just a single rental property means it could equally have been a loss if market conditions were different. I think he made the right move to simplify his portfolio, because although his retirement time horizon is decades out, he only has so many years to be a doting father. Life changes should ideally not cause one's portfolio to be overhauled.

This is not AI text and you're the one who's departed from the OP's request:

I am standing up a wiki

The definition of a wiki is unambiguous:

A wiki (/ˈwɪki/ ⓘ WIK-ee) is a form of hypertext publication on the internet which is collaboratively edited and managed by its audience directly through a web browser.

The entire context of OP's post is web, ie the Internet. We are not taking about physical book libraries. We aren't discussing microfiche. The only relevant database type germane to OP is a relational database, as you readily noted:

If you do additional web application mumbo jumbo, you might need a relational database

I'm personally weary of software that tries to do IP-level allow/deny, because it's effort spent on a feature that either is rarely used (ie most users' threat model presume the LAN is safe) or it would get heavily used and its performance becomes a limiting factor (eg WAN exposed service). There isn't really much of an in-between here, and so I generally ignore such features and would use a proper software firewall to reject at the network level. A firewall can also do rate limiting, and other things like permitting blocked IPs to have another go after a cool-down time.

But supposing you still want to proceed, what you've described would cover the simplest case, yes. But consider that firewall rules often allow you to have ordered rules, such as: block by default, but allow anyone from 2001:db8::/32, but reject from 2001:db8:69::/64, except that 2001:db8:69::420/128 is cool and should be allowed. Here, that would be four rules for a firewall like Linux nftables or FreeBSD pf.

In your case, how many entries would it take to convey the same intent, where there are "enclaves" to the allowlist? This is the sort of complexity that firewalls have already solved, and if it's a matter of integrating a dynamic block feature into your app, you could just have your app tie into the OS firewall. Any firewall worth its salt will have APIs to do that, such as pf's in-memory "tables" that are a list of all IPs that are grouped together to apply a rule. These are expressly designed to be added to/remove from frequently and efficiently. The rule doesn't change, but the table of IPs affected would be updated by your app.

The filesystem is a database as well.

Only in the most reductionist sense would this be true. In practice, a relational database (ie has a schema and querying language) is no replacement for a hierarchical filesystem, and vice versa.

A filesystem stores binary blobs of data, and its up to each file format to define the semantics of the data contained. A database is a data structure coupled with accessors to present and cross-reference structured data. Trying to do a LEFT-JOIN on three binary files is a category error. And storing a PNG in a MariaDB table would be a sort of malpractice.

A closer comparison would be an SQL database versus a data serialization format like YAML. Both have structure and have data that can be acted upon in specific ways. Arithmetic can be performed on numeric values, and strings can be concatenated together. But neither will let you concatenate numeric values, such as 2 + 2 = "22". You need a programming language like PHP to perform such shenanigans.

In the context of serving web content, the filesystem is the domain of the OS, meaning it has been honed by decades of experience to make it as performant as possible, built into the kernel to utilizing whatever caching tricks that make sense, and this is available irrespective of the specific userspace stack (eg LAMP) that is running. However, no mainline OS has a relational database built into the kernel and is available for a web application to use. Database engineers go through great pains to optimize a system to run as a database server.

Phrased another way, there are no mainline OS's that omit the filesystem. So removing the need for a relational database is removing an attack surface, removing a dependency, removing another thing that can break. The point of a database is to look up pieces of data. But if a web server can just serve up a whole HTML file that includes all the data needed, then the database can be omitted and performance will be higher as a result.

Can a filesystem be used in lieu of a database? Sure but there are many things which can be done but shouldn't in all normal circumstances. That is the crux of engineering: to select the right tool for the job.

If scale is a concern, then you want to be reducing drag as much as possible. Database lookups and edits can get expensive, so maybe just avoid them outright: DokuWiki only requires a web server with PHP. It keeps content as plain files, making it easy to serve up and to back up.

But it's often said that perfection is when nothing can be taken away, so what if we remove PHP as well? In this case, we need the content to already be rendered HTML. And we can do that, since there's a body of site generation packages that build from Markdown files. I found this one while randomly searching: https://codeberg.org/milofultz/swiki

At this point, it's just a plain web server that dishes out static HTML files. Such simplicity will withstand most AI scrapers, because the cost per request is now absurdly low. And caching a static site is not particularly difficult. Indeed, if the sum total of the wiki content is small enough, it might even fit into something like Codeberg Pages, which means we've eliminated even the web server (though this would depart from c/selfhosted).

What seems to be missing from that swiki package -- but is entirely feasible -- would be to have all content in Markdown files and live in a Git repo, and the Git history itself is used as the Wiki history. This means your pages would retain the classic wiki change log, so that it can all be generated from a Git repo that's small enough to keep on a floppy disk.

Simplify, then add lightness.

on Megolm Key Confusion · c/crypto · 2 pts · 3d

Adding more background, Soatok previously looked at libolm (the library specifying the peer to peer racket cryptography) and Megolm (the specification of the group racket cryptography). And the takeaway back in 2024 was that:

The people that developed Olm and Megolm has not proven themselves ready to build a Signal competitor. In [sic] balance, most teams are not qualified to do so.

And back then in 2024:

3 of the 16 clients surveyed use the new vodozemac library. 10 still use libolm, and 3 don’t appear to implement end-to-end encryption at all.

Deprecation policies are a beautiful lie. The impact of a vulnerability in Olm or Megolm is still far-reaching, and should be taken seriously by the Matrix community.

So the fact that a key confusion vulnerability exists in the latest Megolm specification -- nevermind whether it's actually translates to a vuln in the main Element client's vodozemac Rust implementation -- is damning and reiterates Soatok's earlier takeaway.

I want Matrix to succeed, to add to the list of reliable E2EE software that currently has just one real entrant (Signal). But project management is failing Matrix right now, and it's showing through these sorts of technical mishaps. The demand and will to develop a bona fide, federated E2EE competitor is there, but the actual implementation is not.

And it's not clear that things will get better anytime soon. The timeline matters, because a number of people genuinely cannot use Signal and need an alternative. But Matrix either isn't it, or it's failing to deliver on the federation aspect that was meant to be its distinguishing strength. This is a Matrix problem at large, not just a problem for Element interoperability, and not just a problem for older non-Element clients. The Matrix project owns the spec and they alone need to do something about it from the top.

As a counterpoint (but one which admittedly doesn't include the complexity of cryptography), ActivityPub is a protocol specification that laid down the ground rules and many compatible software stacks implement it with fairly good interoperability. You reading this very post proves that point. If there was, say, a flaw in moderation capability using the protocol, it wouldn't make sense to blame the Lemmy client, or kbin software, or the default Android Mastodon client. No, the responsibility has to befall the protocol itself, because it affects everyone, even if some instances aren't yet impacted.

I think this community is meant to highlight new sentences never before uttered in the English language; if a 19th Century author is writing it, that's not quite nouveau.

That said, I won't poo poo on your https://xkcd.com/1053 moment to enjoy the works of the esteemed American author and his glorious writing style.

When I think of "offering a domain", I immediately think of DNS subdomain delegation. And on the linked page, you do say "DNS alteration encourage", which could suggest that subdomain delegation is what you had in mind.

But the rest of the text suggests more than subdomain delegation? How do you envision that self-hosted services might operate underneath the "top level" domain if not by delegation? Do you mean that an API would not create a delegation but would simply create a single record?

To be clear, a delegation of "xyz" under example.org would mean that some other DNS server is now authoritative for the entire *.xyz.example.org tree in DNS. That allows the delegate to create their own records for foobar.xyz.example.org or mail.xyz.example.org. Whereas if there was just a single AAAA record named "xyz" under the example.org domain, then the only name that will resolve is xyz.example.org; there is no additional authority to create subdomains under xyz.example.org.

In either case (a delegation or single records), you could certainly develop an API or some sort of Git repo as the source that is referenced by the top level domain's nameserver. This is quite similar to how DDNS providers work. And a while ago, someone on Mastodon (I think) used a custom nameserver to send football/soccer scores via DNS lookups. Or tunneling IP itself over DNS.

In the non-delegation case, some services might need more than one record created. For example, a simple web server at the xyz.example.org subdomain needs at least two fecords (A and AAAA) to support both Legacy IPv4 and modern IPv6 clients. If doing an email server, it would need at least an MX record, but modern DKIM and SPF might require additional TXT records and maybe SRV records.

For folks that are space constrained and would only use a trailer infrequently, folding utility trailers are available. Specifically, Harbor Freight in the USA sells one such 4x8 utility trailer for some $400. It weighs 250 lbs, though closer to 300 lbs (180 kg) after adding a 5/8" (10 mm) plywood deck; not included.

This makes it fairly reasonable to tow even with a small car, for light-but-bulky payloads (eg sectional sofa) a few times per year. Some US States like Oregon don't even require registration for such small trailers, while California has an extremely reasonable $25 plate fee that lasts 5 years.

To be abundantly clear, towing anything is a departure from run-of-the-mill driving, and carrying a load of any size presents hazards that require some attention and care. But it's entirely feasible and costs a lot less than a truck. The tradeoffs can be worth it, if it works with your use-case. It certainly does for mine.

Congrats! On the other hand, you will now be getting an influx of calls from friends whenever they're buying something from the home improvement store and it's too big to fit inside their car lol

In some cases, the game server's IP address is actually anycasted, which is an approach that (very carefully) breaks the notion that a network identity belongs to a single machine. Instead, that one IP address would actually be routed to a nearby machine which is authorized to assume the identity of the game server, and will thus handle the game traffic for that region. So long as all regions handle their traffic identically and the results are consistent as if there were one giant machine that were handling all the traffic, this can work. An example where the seams are visible are how YouTube's view counters will momentarily not match up across all geographies, because the backend servers don't sync up to each other instantly or even quickly; and few people require that precision anyway, so they just don't bother engineering it to do that. When you're providing a global service, that is exactly the sort of engineering tradeoff that must be considered, because even they do not have unlimited money.

In other situations, the game server IP address really is for a single machine, but that machine is a specialized hardware load-balancer that is situated in a cloud provider's network. All that this machine does is to be the frontend for the 5-tuple, and will create a new conversation/connection 5-tuple with a cluster of game servers within the cloud provider's network. There might be some superficial comparisons between a load-balancer and NAT, but the latter works by fraudulence whereas a load-balancer is a subcontractor.

The other commenters have provided many disparate answers that do reply to parts of your question, but allow me to approach the question holistically and thoroughly.

my basic understanding is that computer networking relies on constructs like IP addresses and port numbers to direct data packets to the correct device and application.

This is substantially correct. An IP address is a network identity of some "node" machine that participates on the network. A port number is a protocol-specific number for how to interact with a given node. For gaming, we are almost always talking about UDP as the protocol, so the port number will be a UDP port number; the same logic applies for TCP, but I'm going to gloss over that unless you specifically want details about this.

In the case of Legacy IPv4, an IP address is a 32-bit number that is usually presented as four decimal bytes separated by dots (eg 203.0.113.67). Or for modern IPv6, it will be a 128-bit number presented as hexadecimal groups of double bytes that are colon-separated, but where zeros can be abbreviated (eg 2001:db8::67). A TCP port number is any value between 1 and 65535 inclusive; 0 is technically usable but most software will not allow its use.

So, if I’m playing an online game like Minecraft or Counter-Strike, I am able to connect to the dedicated game server using the server’s IP address ... and port number

Correct. Your client aims at the server's IP address, and the UDP port number on that server. And on your end, you will have your own client IP address and client UDP port number. Implicit to the internet, we know that this must be using IP (v4 or v6 does not matter in this scenario) and the client and server only know how to speak UDP. Thus, there are five pieces of information which capture the entire connection: the source IP, source port number, destination IP, destination port number, and the protocol (UDP). In the networking parlance, we call this as the 5-tuple, because it captures the notion of a single conversation between two applications across the network.

Note that I'm specifically using the word "conversation" and not "connection" because the latter has a specific meaning in the business. A connection means that we're holding a resource open -- like a telephone line --for the entire duration that data is being exchanged. But UDP doesn't reserve resources like that, and is more like sending a post card and hoping for a reply.

The 5-tuple concept is important because like an IRL conversation, it's entirely possible to send data in the reverse direction, and while the source IP/port and destination IP/port will be reversed, it's easy to see that this is functionally the same "conversation", just in reverse. The network doesn't really care if the tables have turned: it just passes packets around. So I will simplify and say that if a 5-tuple reverses its source and destination values, then that's functionally no change at all.

I can now answer your question with technical precision: a game server can distinguish multiple game clients by using their unique 5-tuple. The rest of your question is answered by a brief explanation of various workarounds that are needed for the post-1995 Legacy IPv4 world, but which were fixed in the modern IPv6.

In some cases, each client will be connecting from their own network modem, with their own IP address assigned to them dynamically or statically by their ISP. In that case, I would imagine that the server could just keep a list of client connections and route relevant data back to each client.

This is exactly what existed pre-1995 when the end-to-end principle was alive-and-well on the public Legacy IPv4 Internet. As I mentioned before, an IP address is a network identity, and in the original conception of IP going back to ARPANet, an identity was not meant to be shared amongst multiple machines. Instead, every machine was expected to have its own IP address. However, during the 1995 explosion of dial-up users, network operators could not (or would) not) obtain new tranches of IP addresses to hand out to users, so they began using NAT as a workaround, to reduce their need for public IP addresses. But the keyword was "reduce" not "eliminate", and by 2012, the world had officially run out of available IP addresses to hand out to ISPs.

But in other cases, you might have a multiple clients playing a game behind one modem (like housemates or a LAN party where multiple players join the same remote/internet server), or a newer problem, multiple different networks sharing an IP address due to CG-NAT at the ISP level.

All of these workarounds (NAT/NPAT, CG-NAT, etc) all work by mutilating the 5-tuple and then unmutilating it for return traffic. When a home router performs NAT, it replaces the client's source IP (eg 192.168.3.42) with the router's (eg 203.0.113.67), and usually also replaces the client's UDP port (eg 12345) with a random one available on the router (eg 45467). The resulting 5-tuple is what the game server will receive. NAT must save the mapping (12345 -> 45467) for future reference.

When the game server wants to reply, it will -- exactly the same as the case with the end-to-end principle -- reverse the source/destination fields in the 5-tuple, and send the packet. This means the destination is now the home router's IP (203.0.113.670 and UDP port (45467). What NAT will now do is to again modify the source IP (to restore the original value of 192.168.3.42) and then use its stored mapping to restore the original UDP port number of 12345.

From the client's perspective, it receives a reversed 5-tuple of the one it sent to earlier. Thus, it's perfectly happy to receive that traffic and nobody is the wiser.

In which case, from the perspective of the server, multiple players would be playing from the same IP address and communicating over the same port, right?

Recall that NAT on the router will: 1) generate a random, new UDP port number, and 2) store the mapping of the originator's port number. So if there are two clients at home playing Minecraft, the router will have generated a different random UDP port number for each, meaning the 5-tuple that arrives to the game server will match 4 out of 5 parts, but not all five. The crucial -- and only -- distinction between these two clients at the same house are that they present a different source UDP port number to the server. And that is also how the game server will treat those two clients separately.

If the home router were to spontaneously reboot -- thus forgetting the NAT mapping table for UDP port numbers -- then both clients cannot recover the conversation at all, even after the home router is back online: the mappings are lost, and nothing can be done but to reconnect to the game server as a new 5-tuple. The end-to-end scenario does not have this problem, and pre-1995, routers did in-fact crash more often than they do now. Genuinely, today's Legacy IPv4 service is poorer than it was in the past, and certainly poorer than what modern IPv6 can deliver.

So how does the server differentiate between >2 players connecting from the same IP address and communicating over the same port?

As long as the home router has available UDP port numbers, NAT can continue to randomly generate a unique UDP port number for each client that is behind the NAT. Since UDP port numbers can be as large at 65535, that's a lot of clients. Though practically, no home router would ever see that many Minecraft clients. Even CG-NAT tends to only support approximately 64-128 clients on a single Legacy IPv4 address.

As for why, all this mutilation of packets takes a little bit longer than just passing the packet through the internet. It is not fun for the ISP to have to build CG-NAT infrastructure. It is not fun to build home router firmware that will get blamed for the user's bandwidth or firewall problems. Also, NAT would require a (relatively large) table in memory store lots of mappings, and so they just don't do that for consumer routers.

In the USA, AT&T's fibre internet modem/router is known to max out after a critical number of UDP conversations or TCP connections, because the NAT feature has run out of memory. This is precisely why some people bypass the modem/router (so they can use their own high-end router) or will use IPv6 for their connection-intensive workloads, like sharing Linux ISOs.

Or does it not even try, and instead just broadcast all of the relevant game data to every client?

Game servers definitely do not do this, because broadcast is not permitted on the public Internet whatsoever, whether on Legacy IPv4 or modern IPv6. The original conception of the internet did describe "multicast" which can target a group of IPs on a network, but this was never well-implemented for IPv4 and is only implemented on LANs for IPv6. The public internet does not support multicast, for a number of historical and bandwidth/security reasons.

If a game server wanted to send the same data to each client, one after another, it can. But it still must know the 5-tuple that identifies each client. Fortunately, the game server's OS will have taken care to record this info (eg BSD sockets).

And if that’s the case, how do huge games like battle royales or MMOs handle sending game state to a large number of users?

The way that MMOs deal with 100k+ clients goes deep into the realm of clustering, load-balancing, and network engineering. The only things that get more complex than that are high-bandwidth applications involving hundreds of thousands of clients (eg Netflix) or are massive hyper-scaler cloud providers (eg Azure, Alibaba).

That said, the fundamentals are still there: clients are identified by their 5-tuple, and all the engineering done to spread that load must still end up producing a reply that has the reversed 5-tuple.

(cont)

In case this is useful:

If you have a chopstick, you can tape the new string to the back and push the chopstick through the hole to guide the string. Other solid objects like a wire coat hook can work, but you have to make sure the tip won't snag.