oc2 icon indicating copy to clipboard operation
oc2 copied to clipboard

Network Card 2 or "somewhat, but not really NAT"

Open Ktlo opened this issue 3 years ago • 26 comments

TL;DR: I believe that in this mod there should be a extendable Internet card that implements a native network interface in a virtual machine and I can implement it, if possible.

Backstory

While playing with this mod, I quickly began to miss an access to the real Internet that OpenComputers had. I thought it should be possible to send an Ethernet frame to the real system via the TAP interface in order to gain access to the real Internet effortlessly. I did it and got what I wanted. Unfortunately, this is not the best solution for OC2. However, we can make an Internet card that implements "somewhat, but not really NAT".

What do I suggest?

I propose to create a Java interface for each layer of the TCP/IP stack, starting with the link local layer and ending with the transport layer: LinkLocalLayerInterface, NetworkLayerInterface and TransportLayerInterface. Each interface will have the default implementation: DefaultLinkLocalLayer, DefaultNetworkLayer and DefaultTransportLayer. Objects of the DefaultLinkLocalLayer and DefaultNetworkLayer classes will be a composition of the implementation objects of the upper layers (new DefaultLinkLocalLayer (new DefaultNetworkLayer (new DefaultTransportLayer ()))).

Each interface will unpack and pack each next layer of the TCP/IP stack. For example, the transport layer interface will work with TCP streams, UDP messages and some ICMP messages (Echo Request / Respond).

In addition to interfaces, there will be a BasicInternetCardItemDevice class similar to the NetworkInterfaceCardItemDevice class, which will use the implementation of the LinkLocalLayerInterface interface to operate.

The DefaultTransportLayer implementation of the TransportLayerInterface will use Java sockets, thereby implicitly performing NAT.

Why not an addon for OC2?

I think it makes sense to make this part of the main mod for a number of reasons.

  1. Interfaces LinkLocalLayerInterface, NetworkLayerInterface and TransportLayerInterface can be used to create their own Internet cards by authors of addons for OC2. LinkLocalLayerInterface can be used for TAP interfaces. NetworkLayerInterface is suitable for TUN interface. TransportLayerInterface can be used to connect to a SOCKS server in purpose to secure the internal network where Minecraft server is located.

  2. Access to the Internet can be very convenient for developing programs. For example, I have compiled an SFTP-Server for a virtual computer and now I can write Lua scripts from VSCode. It would be nice to have a similar set of tools so that it is not that difficult to play.

  3. Someday Alpine Linux will be ported to RISC-V. Alpine Linux uses the same programs as Buildroot, but it also comes with a handy apk package manager. This may become the standard way to install additional software in the future. The apk needs the Internet to work, of course.

What remains unclear?

Several questions require answers.

  1. I want to try to do this, but will you accept such contribution?

  2. If you accept it, is it worth changing something in the original idea?

  3. I think that among the items of the mod there will be "oc2:internet_card" using the default interfaces implementations. But won't this be a security hole in the game server? Most likely, there should be an option in the configuration, where "oc2: internet_card" will initially be disabled.

Ktlo avatar Aug 02 '21 14:08 Ktlo

An internet card would indeed be nice. I'm just being super paranoid about opening the local network of a Minecraft server to any players on it, so I haven't done too much research on this myself :) If you're saying there's a way to do this reasonably safely, nice!

I might still lean towards having this item disabled by default, because, again, paranoia. Opening up relatively low-level networking vs. the relatively high level HTTP requests in OC seems just somewhat scary.

To answer your questions:

  1. Yes, if:
    • It doesn't require any native libraries (my initial research into TAP indicated that at least that's not possible without?)
    • It's either disabled by default and clearly labeled as a security risk for the server owner, or it's reasonably safe for server owners but can still be disabled. By "safe" I'm thinking: no access to local network resources, only general internet, non-trivial to DDOS/spam/etc from within the mod.
  2. I'll be honest, my memory on the (in particular lower) network layers is rather rusty. What you describe sounds reasonable, though I'm wondering if, given said security concerns, the highest layer would be sufficient? But I guess since the lower ones will be necessary for that anyway, for decoding in software, I'd trust you it makes sense to split those up anyway. That aside, no immediate concerns.
    • A question: I suppose all of these would build on top of the VirtIO network card, and just process the packets further? Instead of just forwarding like the current world-internal implementation?
    • Something to ponder: statefulness, i.e. game save/load. Would it be reasonable to simply not persist any internal state, leading to the same effect as packet loss?
  3. Yeah, oc2:internet_card would be most fitting. And yeah, as mentioned above. Unless some sane quasi-sandboxing is possible, should probably be disabled by default. Still, would definitely be nice to have and make life for those not running a public server with untrusted clients a lot easier (and cooler :P)

fnuecke avatar Aug 02 '21 22:08 fnuecke

At the moment, I use the TAP interface, it was faster and easier to implement, but I understand that such a solution is not suitable for several reasons: it requires administrator rights, it is difficult to configure, on Windows it requires a special driver, it is impossible without native libraries. Therefore, I will not do this. Worst of all, the cost of moving away from TAP will be the need to implement all TCP/IP in Java.

According to the current idea, I'm going to receive and send Ethernet frames from the VirtIO network card. These frames will simply be passed back and forth through the LinkLocalLayerInterface implementation. The DefaultLinkLocalLayer class will extract ARP messages from the Ethernet frame to determine the IP address of the interface and its own address. The DefaultLinkLocalLayer will send back and forth IP messages through the implementation of the NetworkLayerInterface interface. The DefaultNetworkLayer class will retrieve TCP, UDP and some ICMP messages and check their integrity. Integrity checking will include checking hash sums and a lot of TCP related stuff. Maybe, I need to separately introduce the SessionLayerInterface for the session layer to make it easier to track.

I think it makes no sense to save these network packets in the state of the game world. It is possible to try to disconnect all the TCP connections of the virtual machine associated with the Internet card when the server is stopped, but I don't think this is necessary.

When I opened an issue, I wanted to make the behavior of the "oc2: internet_card" item strictly final, but at the same time leave the possibility for add-ons to add their own Internet cards using the proposed API. Now I think that this is not quite what we need. The player should not be interested in how the Internet card works on the server. It would be great if he just picks up an item he saw in a single player game. That is, it makes sense to make the functionality of the "oc2: internet_card" item be possible to override. I think it can be done via ServiceLoader. The artifact of the OC2 mod will be the same on the server and on the client, but the server administrator can change the behavior of "oc2: internet_card" by adding an artifact with different functionality of "oc2: internet_card" item.

Something about HTTPS

I also thought it would make sense to go to the upper layers and do something for HTTP. I tried to compile OpenSSL for RISC-V and without documentation it weighs in ~13MB. Even if it were possible to achieve a small size of OpenSSL, I would like to avoid cryptographic operations on virtual machines in the game. But now almost all sites have switched to HTTPS. These facts together make the Internet card a little useless. However, this problem can be solved by adding one tricky functionality for HTTP. It is easier to explain with an example what is meant.

Let's say a GET request is made from a virtual machine in the game using the link http://example.com/afile.zip. The example.com server responds to this request with a 301 code with the header "Location: https://example.com/afile.zip". But the Internet card will not report such a response to the virtual machine. Instead, it will make another request to https://example.com/afile.zip. All complex cryptographic operations will take place on a real machine, and the response will be returned to the virtual machine in decrypted form, as if the redirect did not occur.

This solution may not work in all cases, but I think it will be useful. For example, someone can make a package manager for Lua scripts to be stored on GitHub. In this case, we are only interested in the authentication of the GitHub server and no confidential data will be transferred in clear text.

Ktlo avatar Aug 03 '21 07:08 Ktlo

The Linux kernel supports hardware implementations of TLS, which I think would be a more logical approach, though I haven't deeply looked at the pros and cons of this.

leo60228 avatar Aug 06 '21 12:08 leo60228

This is just me, but I think an approach that could make more sense might be to have something like an "encryption card" that provides an TLS-terminating HTTP proxy, or something along those lines. I don't like the idea of the network card silently stripping HTTPS, especially if it doesn't help for anything that isn't HTTPS. It could also be useful to see just how slow it is to do cryptography inside the virtual machines.

leo60228 avatar Aug 06 '21 12:08 leo60228

I also thought of another important concern, which is that in a "real" Linux installation users might be more inclined to do things like store ssh keys without thinking of the consequences there.

leo60228 avatar Aug 06 '21 12:08 leo60228

Essentially reimplementing a (pretty much) full network stack does sound pretty daunting, to be honest. Though I guess I'm not one to talk. So. If it works, doesn't take more code the rest of the mod, and ideally comes with some unit tests, cool! Assuming it will be some considerable amount of code, though, it might make sense to turn this into a library that gets pulled into the VM library mod, similar to Sedna, to keep redundant file size low.

Regarding HTTPS: from what I understand, this would present itself as unencrypted to the VM, the way @Ktlo describes it. This might be fine. I like the pointer regarding a hardware support though. Haven't read up on this myself yet, but maybe adding a card device that provides a VirtIO Crypto Device could work. That would seem to be the more desirable approach then, to me.

Re ssh keys: that's a general issue with computer mods IMHO, i.e. users storing sensitive data on their computers which actually live on a server. Some disclaimer could make sense.

fnuecke avatar Aug 06 '21 13:08 fnuecke

I have actually started work in our development branch on creating a tap device. The idea was to make it so the respective block would be creative mode only. Upon placing it it would generate a persistent Linux interface name and then wait for a tap device with that name to appear (with permission to open it). This basically means it requires manual work by both a Minecraft operator as well as a system administrator of the host computer. Minecraft would not do any network configuration, so if you did want any NAT you'd have to configure it yourself. However I haven't gotten very far yet on the actual implementation though.

The general idea is to have exactly one point in the game where in-game and real network connect and just use routing within the game to connect there.

Small additional note: I have also implemented a vlan-capable mac-learning switch. Expect a PR once I clean up the code a bit.

Kilobyte22 avatar Aug 17 '21 18:08 Kilobyte22

@Kilobyte22, you can try out branch in pull request #63 now and implement your idea using internet card. Here an example.

public class TapInternetProvider extends LinkLocalLayerInternetProvider {
    @Override
    protected LinkLocalLayer provideLinkLocalLayer() throws Exception {
        return new TapLinkLocalLayer();
    }
    
    private static class TapLinkLocalLayer implements LinkLocalLayer {
        private final Tap tap = Tap.open();

        public TapLinkLocalLayer() throws Exception {}
 
        // This method will be invoked every game tick in the "Internet thread"
        @Override
        public boolean receiveEthernetFrame(final ByteBuffer frame) {
            // This should work if tap is a non-blocking channel
            int read = tap.read(frame);
            return read != 0;
        }

        @Override
        public void sendEthernetFrame(final ByteBuffer frame) {
            tap.write(frame);
        }
    }
}

To make internet cards pick up your LinkLocalLayerInternetProvider implementation, create a META-INF/services/li.cil.oc2.api.inet.InternetProvider file with the canonical name of your TapInternetProvider implementation.

I think that later I will add some lifecycle methods to LinkLocalLayer interface, because it should be useful for your case. We definitely don't want to create a new tap interface every time we unload and load a chunk with the computer.

Ktlo avatar Aug 17 '21 21:08 Ktlo

I believe a block, rather than a card has more value. In particular it allows to put a switch or hub in between the block and a multiple computers, to have them all be in the same ethernet as each other.

Kilobyte22 avatar Aug 17 '21 21:08 Kilobyte22

While I do see the appeal in a block type device for a server setting, the no-setup "throw card in, works" approach seems more reasonable for local single-player to me. Assuming that's how it'll work, anyway. If they could share a good amount of code, and basically just be two different entry points for the player, having both doesn't sound too bad to me? For consistency (and my peace of mind) both could be creative-only; then in single player people could use the card; on servers the operator could prepare one internet access for players, if desired.

Thoughts?

fnuecke avatar Aug 23 '21 17:08 fnuecke

I tested using wolfSSL, which is explicitly designed for embedded Linux. It seems like a viable solution in terms of code size:

  • BR2_PACKAGE_LIBCURL=y, BR2_PACKAGE_LIBCURL_CURL=y, and BR2_PACKAGE_LIBCURL_TLS_NONE=y: curl is 136K, libcurl.so.4.7.0 is 272K
  • BR2_PACKAGE_WOLFSSL=y, BR2_PACKAGE_LIBCURL=y, BR2_PACKAGE_LIBCURL_CURL=y, and BR2_PACKAGE_LIBCURL_WOLFSSL=y: curl is 136K, libcurl.so.4.7.0 is 304K, libwolfssl.so.24.2.0 is 396K

Ignoring things like documentation, this is a net increase of only 428K, which is far less than 13MB for OpenSSL.

leo60228 avatar Aug 23 '21 18:08 leo60228

Personally, I find the “internet” block idea very beautiful. Thus, you can connect the real world with the game world directly and send broadcast messages at the link local layer to both real devices and computers in the Minecraft world. However, this is the only thing that the block approach gives and that the internet card alone cannot offer. However, you can still do this by using interface bridging in a virtual machine.

A virtual computer with an internet card and a network interface card can act as the main gateway on the game server. In this case, internet card craft recipe can be disabled. Thus, the Minecraft server administrator will still have control over all Internet access points, if necessary.

We can try to make both an internet block and an internet card. However, there is a problem that prevents the use of the same code for their implementation. The current implementation of the Internet card (#63) by default simulates a network device at the link layer, which determines its IP address using the ARP protocol. This is a hack that works thanks to "Who is?" requests. This is possible only if it is known that there are only 2 devices in the channel: a virtual computer and a simulated network device. You can think of another way to determine the IP address of the simulated device, but it should be borne in mind that the server administrator should still be able to replace the implementation of the internet card. Therefore, I believe that such parameters should not be set from the game world.

Now setting up an internet card looks like this:

# eth0 is an interface provided by internet card
ip link set eth0 up

# Can be any subnet, but it is reasonable to assign p2p subnet address with prefix 30
ip addr add 192.168.2.1/30 dev eth0

# Assign address to the host simulated by the internet card
# This host will be gateway, obviously
ip route add default via 192.168.2.2

Everything else is determined by the default implementation of the internet card itself, using the proposed configuration.

One of the solutions to the problem, which I can offer, is to set an IP address in the mod's configuration. Thus, all internet cards will have the same IP address. After that, the implementation of the Internet card and the Internet block can be the same.

Ktlo avatar Aug 23 '21 20:08 Ktlo

The general problem of having a "works without configuring anything outside of the game" requires the end-user to have network admin privileges (CAP_NET_ADMIN on linux, i imagine it needs admin access on mac/windows as well). Giving such access to a game is questionable, especially for such a feature.

The only real solution would be to perform some kind of NAT in userspace, similar to how sshuttle works. This can be done, but is a lot of work. (To my understanding that is what Ktlo is trying to achieve, correct me if wrong)

An alternative might be a card that provides a BSD socket like api, allowing TCP and UDP, with the disadvantage that it does not integrate at all with existing linux tooling.

I believe a mix of those solutions might be a good way. An example might be Userspace NAT by default, but config option to switch it to a straight tap interface. This would mean it would generally "just work" but not have full potential. When an admin wants more, they can upgrade to the tap interface which needs configuration of the OS anyways, so having to change a config option is completely fine as well.

Kilobyte22 avatar Aug 23 '21 22:08 Kilobyte22

While I do see the appeal in a block type device for a server setting, the no-setup "throw card in, works" approach seems more reasonable for local single-player to me.

Personally I'm more of a fan of the block idea ("Modem"), mainly because it adds an extra challenge to a very powerful in game feature, also it's more analogous to what you see in real life.

logan2611 avatar Oct 31 '21 19:10 logan2611

For what it's worth, if RISC-V cryptography is too slow, there are still options I'd consider cleaner than transparent HTTP/HTTPS proxying. wolfSSL supports cryptodev-linux, so a virtio-crypto driver could be implemented so that TLS in the guest can make use of Java cryptographic operations.

leo60228 avatar Jan 10 '22 19:01 leo60228

What is the intended set of allowed actions / protocols? If only outgoing TCP is to be allowed like in OC1, then maybe expose just that socket interface directly, and if needed run a transparent socks5 proxy on the in-game computer? (Does the "stock" OC2 kernel come with iptables?) Maybe also add a parameter to enable SSL on Java side for the socket.

evg-zhabotinsky avatar Jan 11 '22 16:01 evg-zhabotinsky

Just two cents, i would love to be able to enable this as a full NAT for whitelisted servers with friends that you trust. Because i just installed the mod for the first time and one of the first thing i tried was ssh-ing to my server. ;)

Linux running on Minecraft running on Linux, what a time to be alive! <3

bastetfurry avatar Feb 15 '22 20:02 bastetfurry

i would love to be able to enable this as a full NAT for whitelisted servers with friends that you trust.

It sounds to me like you want that NAT to tunnel back from the servers to your PC. Did I get this right? (If not, what do you mean by "whitelisted servers"?) If so, the idea is quite interesting, though giving the other players easy access to your real network doesn't sound safe. In any case, would be nice if Minecraft client could forward some ports (or a whole Socks5 proxy) towards some network card(s) in-game. (Maybe a linked card that is in logged in player's inventory? Or a "Personal modem" that gets linked to a player somehow.) It doesn't need to forward the other way around (except for TCP replies to the incoming connections), so should be relatively safe, and would eliminate the need for using a relay with public IP or opening any extra ports on the server when you want to connect to in-game computers. And then, if you really want to, you can forward everything you want to back to your real PC through SSH or some other tunneling method. That could even be used to get in-game Internet access on servers where allowing a "proper" Inetrnet card was deemed unacceptable.

Linux running on Minecraft running on Linux, what a time to be alive! <3

Not really, or at least not yet. Though I saw DOS with EGA graphics running (or at least not crawling) on Lua on the old OpenComputers. (See Lunatic86 https://youtu.be/RLAU_JNZwEE) Edit: I can't read. I saw "Minecraft running on Linux running on Minecraft".

evg-zhabotinsky avatar Feb 16 '22 06:02 evg-zhabotinsky

@evg-zhabotinsky, i trust my friends to not screw up the server they want to play on so i would love a "NAT-Card" that would let them reach the outside world much like any VM you could spin up in, for example, QEMU. So for example if they want to connect to some IRC server from ingame they could copy a RiscV compiled BitchX to the RiscV Linux VM and connect to their favorite IRC server. Add a firewall that can block IPs and ports or turn that around and only whitelist IPs and ports for the not so trustworthy servers.

bastetfurry avatar Feb 16 '22 22:02 bastetfurry

@bastetfurry I misinterpreted your post, then. What you describe seems to be exactly what is being implemented already. Have been implemented even, if you don't mind OC having a direct bridge to the host and can set up NAT there. "Proper" built-in NAT with access controls isn't quite done, though, as I understand.

evg-zhabotinsky avatar Feb 17 '22 06:02 evg-zhabotinsky

Possibly interesting idea I had: some (very limited for security reasons) form of port forwarding to the client, for the primary purpose of allowing ssh into computers.

leo60228 avatar Mar 31 '22 19:03 leo60228

I recently returned to the development of the "Internet in Minecraft" with intension to bring it to the end. I have read all the suggestions that have been proposed here and will try to take them into account. Right now, I've already managed to get UDP and TCP up to the point where I can SSH into real servers, but this is very unstable and some things will have to be redone.

In addition to the Internet card, there will be an Internet block that can potentially unite real computers and computers in the game into one channel (one can send BROADCAST and get an IP address from home router).

The emphasis is on providing a convenient API so that alternative implementations of the Internet can be easily made. In other words, It will be easy to change the default Internet implementation to one, that uses socks5 or TUN and TAP network interfaces.

@IntQuant joined me. He is working on the internet block.

I do not want to show the current result yet, because I am not happy with it, but I really hope that I will be able to finish it soon.

Ktlo avatar Apr 25 '22 19:04 Ktlo

any updates on this? I'd love to implement a way to manage/monitor my home lab/servers while playing Minecraft and be able to see in real-time the server utilization via HTOP inside of the game itself!

Mylezz avatar Jun 21 '22 05:06 Mylezz

+1 on this. Would love to SSH to my host computer.

polyzium avatar Jun 21 '22 21:06 polyzium

You can check pull request #63 now. I updated it. TCP is very buggy, but mostly works. I already tried to ssh with it to different hosts.

This pull request does not contain most recent changes, but this version is working a lot better than most recent one. Also, I don't think that it is still a good idea to merge this code to this mod. Right now I'm thinking of creating a separate mod.

Ktlo avatar Jun 25 '22 13:06 Ktlo

That would probably be smart.

CoolCat467 avatar Jun 27 '22 15:06 CoolCat467