<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Marius-Florin Cristian</title>
    <description>The latest articles on DEV Community by Marius-Florin Cristian (@mfc_keibisoft).</description>
    <link>https://dev.to/mfc_keibisoft</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3844364%2F3d4c1171-f666-46a9-81b9-157ec5f41c94.jpeg</url>
      <title>DEV Community: Marius-Florin Cristian</title>
      <link>https://dev.to/mfc_keibisoft</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/mfc_keibisoft"/>
    <language>en</language>
    <item>
      <title>The files are on the NAS at home and the laptop is somewhere else</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sat, 05 Sep 2026 12:24:18 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/the-files-are-on-the-nas-at-home-and-the-laptop-is-somewhere-else-3m66</link>
      <guid>https://dev.to/mfc_keibisoft/the-files-are-on-the-nas-at-home-and-the-laptop-is-somewhere-else-3m66</guid>
      <description>&lt;p&gt;Your files live on a box at home or at the studio. Your laptop is somewhere else. KeibiDrop puts the box's folder on the laptop as a normal folder. You open a file, and the box sends the parts the program reads. The new container runs KeibiDrop on the box. The box is on all day, so the folder is there whenever you open the laptop, wherever you are.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk0hkctnmi9yh16u3la7p.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fk0hkctnmi9yh16u3la7p.gif" alt="Two terminals. Left: the box" width="799" height="405"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Full version, with the limits and the method: &lt;a href="https://keibidrop.com/blog/files-on-the-nas-laptop-somewhere-else.html" rel="noopener noreferrer"&gt;The files are on the NAS at home and the laptop is somewhere else&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Source, MPL-2.0: &lt;a href="https://github.com/KeibiSoft/KeibiDrop" rel="noopener noreferrer"&gt;github.com/KeibiSoft/KeibiDrop&lt;/a&gt;&lt;/p&gt;

</description>
      <category>filesystem</category>
      <category>encryption</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>Two people, one folder, and no lock anywhere</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Fri, 28 Aug 2026 15:13:02 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/two-people-one-folder-and-no-lock-anywhere-4of0</link>
      <guid>https://dev.to/mfc_keibisoft/two-people-one-folder-and-no-lock-anywhere-4of0</guid>
      <description>&lt;p&gt;&lt;strong&gt;KEIBI&lt;/strong&gt;DROP mounts a folder on two machines. Both sides can write to it. And it does this without any server, nor taking an authoritative lock.&lt;/p&gt;

&lt;p&gt;Concurrent edits are quite hard and we resolve them by comparing timestamps and the older save is overwritten without being announced.&lt;/p&gt;

&lt;p&gt;So every change done through keibidrop now carries one extra number: the newest version of that file that the sender actually held when they started editing. If a save arrives with a&lt;br&gt;
number lower than the version I hold, then I know that the sender had not seen my version and the two edits were concurrent.The newer&lt;br&gt;
save keeps the path, the older one is written beside it as&lt;br&gt;
&lt;code&gt;name.conflict-TIMESTAMP.ext&lt;/code&gt;, and that file syncs to both machines.&lt;/p&gt;

&lt;p&gt;Over a real link, Bucharest to Timisoara, ten out of ten steps converged in 0.55 to 0.63 s, and the conflict file reached both machines 0.02 s later.&lt;/p&gt;

&lt;p&gt;Write-up, including why we did not build a CRDT:&lt;br&gt;
&lt;a href="https://keibisoft.com/blog/keibidrop-two-peers-no-locks.html" rel="noopener noreferrer"&gt;Two people, one folder, and no lock anywhere&lt;/a&gt;&lt;/p&gt;

</description>
      <category>filesystem</category>
      <category>distributedsystems</category>
      <category>go</category>
      <category>opensource</category>
    </item>
    <item>
      <title>Triage a remote machine without a VPN</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Fri, 21 Aug 2026 09:03:50 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/triage-a-remote-machine-without-a-vpn-33bb</link>
      <guid>https://dev.to/mfc_keibisoft/triage-a-remote-machine-without-a-vpn-33bb</guid>
      <description>&lt;p&gt;A computer somewhere else on the internet holds files you need to look at. Today that usually means one of two things. Somebody arranges a VPN into that network, which takes days and a change request. Or somebody copies the whole disk out and sends it over, which starts a transfer with an ETA measured in hours. Either way, you wait before you can look at anything.&lt;/p&gt;

&lt;p&gt;With KeibiDrop, the folder on that computer shows up on yours as a normal folder. You can browse it, search it, and copy out the files you want. Only the bytes you actually read travel across the link.&lt;/p&gt;

&lt;h2&gt;
  
  
  This is what it looks like in a terminal
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;ls &lt;/span&gt;K:&lt;span class="se"&gt;\h&lt;/span&gt;ost1&lt;span class="se"&gt;\W&lt;/span&gt;indows&lt;span class="se"&gt;\S&lt;/span&gt;ystem32&lt;span class="se"&gt;\w&lt;/span&gt;inevt&lt;span class="se"&gt;\L&lt;/span&gt;ogs
&lt;span class="go"&gt;Application.evtx  Security.evtx  System.evtx  ...

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-rl&lt;/span&gt; &lt;span class="s2"&gt;"ATTACKER-IOC"&lt;/span&gt; K:&lt;span class="se"&gt;\h&lt;/span&gt;ost1&lt;span class="se"&gt;\i&lt;/span&gt;netpub&lt;span class="se"&gt;\l&lt;/span&gt;ogs
&lt;span class="go"&gt;K:\host1\inetpub\logs\LogFiles\W3SVC1\u_ex260715_042.log

&lt;/span&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;robocopy K:&lt;span class="se"&gt;\h&lt;/span&gt;ost1&lt;span class="se"&gt;\W&lt;/span&gt;indows&lt;span class="se"&gt;\S&lt;/span&gt;ystem32&lt;span class="se"&gt;\c&lt;/span&gt;onfig C:&lt;span class="se"&gt;\e&lt;/span&gt;vidence&lt;span class="se"&gt;\c&lt;/span&gt;onfig /E
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;These are all commands an examiner already runs every day. KAPE accepts the mount with &lt;code&gt;--tsource&lt;/code&gt; and needs no changes to work with it. The mount behaves like a real filesystem, so there is nothing to import and no new application to learn.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/Y_4PZcqr4U4"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;p&gt;The video is one run from beginning to end, and none of the commands are cut out of it.&lt;/p&gt;

&lt;p&gt;A Mac is holding 2,683 files that come to 19.9 GB, and a Windows laptop mounts that folder read only. You can watch the tree get listed, then a grep go through every log in it, then robocopy pull out the artifact set, and at the end both machines hash the same two registry hives and compare them.&lt;/p&gt;

&lt;p&gt;Over the whole session, 606 MB crossed the link against the 19.9 GB that was sitting on the Mac, which works out at 34 times less data. We take that 606 MB off the network card, so it includes the grep, which had to read every log in the tree to answer the question. The artifacts that ended up on disk came to 382 MB. Both machines were in the same apartment in Bucharest on one Vodafone line that gives 498 Mbps down and 50 Mbps up at 27 ms, and the traffic was relayed through Timisoara and back, so the two of them were sharing the same uplink the whole time. The hashes matched on both sides, nothing on the Mac changed, and the access times stayed where they were.&lt;/p&gt;

&lt;p&gt;Do not read the clock in that video as a speed you would get. Pulling the artifact set took just over seven minutes, and it was slow because there were 2,174 separate files in it and every one of them waited for its own round trip to Timisoara and back. We have rewritten that part since the recording, and there is a &lt;a href="https://keibisoft.com/blog/keibidrop-small-file-walk-batching.html" rel="noopener noreferrer"&gt;write-up with the measurements&lt;/a&gt;. The evidence tree you see was generated for the demo, so the file names look right and a real parser rejects the contents.&lt;/p&gt;

&lt;h2&gt;
  
  
  You see the whole folder before any file content moves
&lt;/h2&gt;

&lt;p&gt;The file listing is sent first, and it is small. It costs about 73 bytes for each file, so a folder holding 10,000 files announces itself in about 732 KB. That measurement took 116 ms, on a loopback pair with both programs running in one process. Over a real network link, add roughly one round trip for every 256 files. The cost per file stays the same.&lt;/p&gt;

&lt;p&gt;This is what lets you look before you fetch. You can see everything that is there, and then decide which files are worth opening. On a link with 17 ms of round trip time, opening a file from the mount took between 30 and 40 ms.&lt;/p&gt;

&lt;h2&gt;
  
  
  Read only is enforced on the computer holding the files
&lt;/h2&gt;

&lt;p&gt;Turn on &lt;code&gt;share_read_only&lt;/code&gt; there and it refuses every write coming from the other side, before anything reaches the disk.&lt;/p&gt;

&lt;p&gt;This setting works even with the filesystem driver switched off. That matters here, because it means the computer holding the files runs one ordinary program in user space. There is no kernel driver to install on it, and no reboot.&lt;/p&gt;

&lt;p&gt;On the receiving side, turn on &lt;code&gt;preserve_metadata&lt;/code&gt; and the files you copy out keep the permission bits, modification time and access time they had on the source.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Attribute&lt;/th&gt;
&lt;th&gt;What happens to it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Permission bits&lt;/td&gt;
&lt;td&gt;Applied to the file you receive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modification time&lt;/td&gt;
&lt;td&gt;Applied to the file you receive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Access time&lt;/td&gt;
&lt;td&gt;Applied. On Linux and Windows, serving a read leaves the access time on the source alone&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Birth time&lt;/td&gt;
&lt;td&gt;Travels across the link and is visible through the mount. Most systems do not allow writing it to disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Change time&lt;/td&gt;
&lt;td&gt;The kernel maintains this one. No tool can set it&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The access time row works differently on macOS, which has no per-handle equivalent of the Linux &lt;code&gt;O_NOATIME&lt;/code&gt; flag. There the volume decides, so it depends on how the volume was mounted. We measured this and wrote up &lt;a href="https://keibisoft.com/blog/macos-atime-noatime-forensics.html" rel="noopener noreferrer"&gt;the mount option that keeps access times unchanged&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Neither side needs an inbound port
&lt;/h2&gt;

&lt;p&gt;Both computers connect outbound and find each other that way. You do not have to open a port on the firewall in front of the source, and you do not have to install an SSH server on a Windows host. When there is no direct path between the two, the traffic goes through a relay instead. The relay cannot read any of it, because the session is encrypted end to end.&lt;/p&gt;

&lt;h2&gt;
  
  
  We built this for triage and for passing evidence between analysts
&lt;/h2&gt;

&lt;p&gt;Forensic imaging is a different job and it stays with the tools that do it. Locked registry hives and Volume Shadow Copies need raw NTFS reads, so the collectors that run on the machine itself still handle those.&lt;/p&gt;

&lt;p&gt;Appliances are a separate case. ESXi and network gear will not run a new program at all. To reach one of those, mount its datastore on a Linux host where you can run software, and share that folder instead.&lt;/p&gt;

&lt;h2&gt;
  
  
  This needs a FUSE driver on the machine doing the reading
&lt;/h2&gt;

&lt;p&gt;The mount uses FUSE, and it goes on the analyst's computer. Install &lt;a href="https://winfsp.dev/" rel="noopener noreferrer"&gt;WinFsp&lt;/a&gt; on Windows or &lt;a href="https://macfuse.github.io/" rel="noopener noreferrer"&gt;macFUSE&lt;/a&gt; on macOS, and on Linux &lt;code&gt;libfuse3&lt;/code&gt; is usually there already. The computer holding the files needs none of it.&lt;/p&gt;




&lt;p&gt;I build KeibiDrop, so read the numbers with that in mind. It is open source and the measurements above are reproducible.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keibidrop.com/for/dfir.html" rel="noopener noreferrer"&gt;Remote triage guide&lt;/a&gt; · &lt;a href="https://keibidrop.com/compare/sshfs.html" rel="noopener noreferrer"&gt;Compared with sshfs&lt;/a&gt; · &lt;a href="https://keibidrop.com/install.html" rel="noopener noreferrer"&gt;Install guide&lt;/a&gt; · &lt;a href="https://github.com/KeibiSoft/KeibiDrop" rel="noopener noreferrer"&gt;Source&lt;/a&gt;&lt;/p&gt;

</description>
      <category>forensics</category>
      <category>opensource</category>
      <category>sysadmin</category>
      <category>security</category>
    </item>
    <item>
      <title>gRPC over QUIC: faster seeks, slower bulk</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sun, 19 Jul 2026 16:33:05 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/grpc-over-quic-faster-seeks-slower-bulk-3ia6</link>
      <guid>https://dev.to/mfc_keibisoft/grpc-over-quic-faster-seeks-slower-bulk-3ia6</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Abstract.&lt;/strong&gt; Notes from testing whether to move KeibiDrop, a post-quantum encrypted peer-to-peer filesystem, from gRPC over TCP to gRPC over QUIC. The product reads remote files on demand, so the goal is to survive an IP change, keep seek latency low, stay correct, then go fast, in that order. Measured on a 12-core macOS laptop, a 4-core Linux VPS, and a real link between a laptop in Barcelona and the VPS at 72 ms round trip. Findings: on macOS the QUIC transport is syscall-bound at about 137 MB/s because the platform has no UDP segmentation offload, and the undocumented &lt;code&gt;sendmsg_x&lt;/code&gt; batching syscall lifts it to about 700 MB/s; a teardown deadlock traced to closing a QUIC stream concurrently with a write, fixed with a stream reset; connection migration moves a live gRPC channel to a new socket, verified with packet counters; on the real WAN a single QUIC stream loses to TCP on bulk transfer by up to 16x under Wi-Fi loss, but a random seek under saturating prefetch lands in 109 ms on QUIC against about 3 seconds on TCP, a 28x difference, because the seek gets its own stream instead of queuing behind the prefetch. The design that follows: the interactive on-demand path over QUIC for seek isolation and migration, bulk on lossy links over TCP.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  The question, and what we optimize for
&lt;/h2&gt;

&lt;p&gt;KeibiDrop is a peer-to-peer filesystem. You mount a remote peer's files and read them on demand. Open a 40 GB video, seek to the middle, and only the bytes you touch cross the wire. The transport underneath is gRPC over our own encrypted TCP connection.&lt;/p&gt;

&lt;p&gt;TCP has one problem we cannot fix from userspace. When the 5-tuple dies, the connection dies. A laptop that moves from café Wi-Fi onto a phone hotspot changes its IP, and the transfer stops. QUIC identifies a connection by a connection ID rather than the 5-tuple, so it can migrate across an address change with the stream intact. We wanted to know whether gRPC could run over QUIC and keep that property.&lt;/p&gt;

&lt;p&gt;We optimize for the experience of an on-demand filesystem, not for bulk throughput in MB/s. The order of priorities is: survive an IP change, keep seek latency low, stay correct, and then speed. All the numbers below are measured. Where a number surprised us, we looked for the cause before believing it. The hardware is a 12-core macOS laptop, a 4-core Linux VPS, and a real link between a laptop in Barcelona and that VPS at 72 ms round trip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Getting gRPC onto a QUIC stream
&lt;/h2&gt;

&lt;p&gt;gRPC already speaks &lt;code&gt;net.Conn&lt;/code&gt;. In KeibiDrop it runs over our encrypted &lt;code&gt;SecureConn&lt;/code&gt;, which is a &lt;code&gt;net.Conn&lt;/code&gt; wrapping a &lt;code&gt;net.Conn&lt;/code&gt;, so QUIC slots in underneath the same seam. The adapter that makes one QUIC stream look like a &lt;code&gt;net.Conn&lt;/code&gt; is small, because a &lt;code&gt;quic.Stream&lt;/code&gt; is already a reliable, ordered byte stream with no framing to add:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;quicConn&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;quic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;            &lt;span class="c"&gt;// Read/Write/deadlines come from the stream&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;quic&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Conn&lt;/span&gt;         &lt;span class="c"&gt;// for the two address methods the stream lacks&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;quicConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;LocalAddr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LocalAddr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;quicConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;RemoteAddr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Addr&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RemoteAddr&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One detail is worth stating now, because it returns in the deadlock section. &lt;code&gt;quic.Stream.Close()&lt;/code&gt; is a graceful, send-only half-close, and quic-go documents that it must not be called concurrently with Write. A &lt;code&gt;net.Conn.Close&lt;/code&gt; has to tear the whole connection down. The correct call is &lt;code&gt;CancelWrite&lt;/code&gt;, a stream reset, not &lt;code&gt;Close&lt;/code&gt;. We used &lt;code&gt;Close&lt;/code&gt; first and paid for it later.&lt;/p&gt;

&lt;p&gt;With the adapter, a listener that hands one stream up as a conn, and gRPC's &lt;code&gt;NewClient&lt;/code&gt; pointed at a &lt;code&gt;passthrough:///&lt;/code&gt; target so it skips DNS, a gRPC call completes over QUIC. Unary, server-streaming, and concurrent calls all work, verified byte for byte and clean under the race detector. gRPC's own TLS stays off. QUIC's mandatory TLS 1.3 sits underneath with a throwaway certificate, because the real confidentiality is a post-quantum handshake we add on top (ML-KEM-1024 and X25519, the same primitives KeibiDrop already uses; QUIC's TLS 1.3 is not post-quantum and ours is).&lt;/p&gt;

&lt;h2&gt;
  
  
  Throughput on macOS
&lt;/h2&gt;

&lt;p&gt;The first benchmark on the macOS laptop streamed a large file both ways on loopback:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;transport&lt;/th&gt;
&lt;th&gt;throughput&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;gRPC over TCP&lt;/td&gt;
&lt;td&gt;1650 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gRPC over QUIC&lt;/td&gt;
&lt;td&gt;140 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Twelve times slower. That is large enough to want an explanation, so we profiled it. A raw QUIC stream with no gRPC gave 137 MB/s, so the gRPC layer was not the cause; the QUIC transport was. The CPU profile showed where the time went:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;56.67%  syscall.rawsyscalln          # the syscall itself
33.33%  ...sendmsg   (one WriteMsgUDP per ~1400-byte packet)
23.44%  ...recvmsg
 0.6 %  crypto (AES-GCM)             # negligible
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Fifty-seven percent of the time was in &lt;code&gt;sendmsg&lt;/code&gt; and &lt;code&gt;recvmsg&lt;/code&gt;. Crypto, which people assume is the cost of an encrypted transport, was 0.6 percent. The reason is that macOS has no UDP Generic Segmentation Offload. On Linux, quic-go hands the kernel a 64 KB buffer and the kernel splits it into packets, so one syscall sends dozens. On macOS there is no such offload, so quic-go sends one &lt;code&gt;sendmsg&lt;/code&gt; per 1400-byte packet. At 137 MB/s that is about 100,000 send syscalls per second and as many receives.&lt;/p&gt;

&lt;p&gt;We checked this by running the same code on the Linux VPS, which has GSO. The VPS is the slower machine (its loopback TCP is 3.4x slower than the laptop's), and its QUIC still ran at 272 MB/s against the laptop's 137. Normalized against each machine's own TCP, QUIC went from 2 percent on macOS to 14 percent on Linux. So the macOS number is a platform limitation, not a design or crypto cost.&lt;/p&gt;

&lt;h2&gt;
  
  
  Batching sends with sendmsg_x
&lt;/h2&gt;

&lt;p&gt;macOS has no GSO and no &lt;code&gt;sendmmsg&lt;/code&gt;. The syscall-batching primitives that fix this on Linux do not exist here. It does have &lt;code&gt;sendmsg_x&lt;/code&gt;, a Darwin syscall that sends many datagrams in one call, similar to Linux &lt;code&gt;sendmmsg&lt;/code&gt;. It is undocumented. The syscall number is in the SDK (&lt;code&gt;SYS_sendmsg_x = 481&lt;/code&gt;), but the &lt;code&gt;struct msghdr_x&lt;/code&gt; it takes is not in any header. You declare it yourself from the XNU source and get the byte layout right, or the kernel reads garbage.&lt;/p&gt;

&lt;p&gt;We wrote a small program that prints the struct offsets, checks them with a real batched send the receiver verifies, and benchmarks batch size against raw UDP send throughput:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;batch&lt;/th&gt;
&lt;th&gt;syscalls&lt;/th&gt;
&lt;th&gt;throughput&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 (one per packet)&lt;/td&gt;
&lt;td&gt;500,000&lt;/td&gt;
&lt;td&gt;390 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;8&lt;/td&gt;
&lt;td&gt;62,500&lt;/td&gt;
&lt;td&gt;675 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;32&lt;/td&gt;
&lt;td&gt;15,625&lt;/td&gt;
&lt;td&gt;701 MB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Batching lifts the ceiling from 390 to about 700 MB/s and cuts the syscall count by 32 times. It levels off at batch 32, where the cost moves from syscall count to per-packet kernel work. So there is a real macOS lever here, about 1.8 times, with no root access. It helps in a second way. The 137 MB/s QUIC transfer used about five CPU cores, all of it the per-packet work TCP hands to the kernel, and in KeibiDrop that CPU competes with the FUSE filesystem, which is busy with encryption and chunking. Fewer syscalls per byte means fewer cores taken from the filesystem.&lt;/p&gt;

&lt;p&gt;The primitive is now in our quic-go fork as the Darwin counterpart of the Linux GSO path, with the verified struct layout, ready to wire into the send loop.&lt;/p&gt;

&lt;h2&gt;
  
  
  The teardown deadlock
&lt;/h2&gt;

&lt;p&gt;The test suite passed under the race detector and hung about half the time without it. That combination points at a timing-dependent bug rather than a random flake, because the race detector slows the code down. The goroutine dump named the test, a client cancelling a server-stream, and showed &lt;code&gt;Server.Stop&lt;/code&gt; blocked while a QUIC write stayed stuck.&lt;/p&gt;

&lt;p&gt;Two guesses were wrong, and both were quick to disprove by measuring. Sizing the download to fit the flow-control window did not help; it still wedged. A short idle timeout had no effect, because a connection that is actively trying to send is not idle. Reading the source settled it.&lt;/p&gt;

&lt;p&gt;gRPC's &lt;code&gt;http2Server.Close&lt;/code&gt; closes the underlying &lt;code&gt;net.Conn&lt;/code&gt;, which is our &lt;code&gt;quicConn.Close&lt;/code&gt;, which called &lt;code&gt;quic.Stream.Close()&lt;/code&gt;, the graceful half-close from the adapter section, the one quic-go says must not be called concurrently with Write. gRPC's writer goroutine was concurrently blocked in a Write on that stream. The contract violation meant the write never returned, the conn never finished closing, and &lt;code&gt;Server.Stop&lt;/code&gt; waited forever.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;quicConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelRead&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;   &lt;span class="c"&gt;// STOP_SENDING&lt;/span&gt;
    &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CancelWrite&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;  &lt;span class="c"&gt;// RESET_STREAM: safe against a concurrent Write, and unblocks it&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CloseWithError&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;""&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Replacing &lt;code&gt;Close&lt;/code&gt; with &lt;code&gt;CancelWrite&lt;/code&gt; turned a 50 percent hang into ten green runs out of ten. The general point: when the race detector flips a test from pass to fail, look for the timing bug rather than adding sleeps. And a lightweight atomic counter is better than a print for diagnosing one, because the print changes the timing you are measuring. Ours made the test pass for a while and pointed us the wrong way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration
&lt;/h2&gt;

&lt;p&gt;Migration is the reason we started. quic-go exposes it directly: &lt;code&gt;AddPath&lt;/code&gt; a new socket, &lt;code&gt;Probe&lt;/code&gt; to validate the path, &lt;code&gt;Switch&lt;/code&gt;. Getting it to fire took reading quic-go's own test. The client has to keep sending after the switch so the peer migrates too, and you must not close the old transport to prove it, because that tears the connection down.&lt;/p&gt;

&lt;p&gt;We checked it with per-socket packet counters, moving a live gRPC channel to a new UDP socket mid-transfer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;migration: local addr 127.0.0.1:52598 -&amp;gt; 127.0.0.1:59126
path 1 writes +0        # old path goes silent
path 2 writes +90, reads +92   # new path carries both directions
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After the switch the old path sent nothing and the new path carried both directions. The gRPC channel kept running. On the real product this is a laptop changing networks during playback without a stall.&lt;/p&gt;

&lt;h2&gt;
  
  
  The real WAN test
&lt;/h2&gt;

&lt;p&gt;Loopback measures a transport's overhead, not its behaviour on a real network. So we ran it for real: a laptop on hotel Wi-Fi in Barcelona, about 45 Mbps down and 72 ms round trip, downloading from the VPS. No emulation and no offload tricks, so both TCP and QUIC send ordinary packets end to end.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;concurrent streams&lt;/th&gt;
&lt;th&gt;QUIC&lt;/th&gt;
&lt;th&gt;TCP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;32.8 s&lt;/td&gt;
&lt;td&gt;2.0 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4&lt;/td&gt;
&lt;td&gt;5.5 s&lt;/td&gt;
&lt;td&gt;1.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16&lt;/td&gt;
&lt;td&gt;4.7 s&lt;/td&gt;
&lt;td&gt;1.7 s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A single QUIC stream dropped to about 2 Mbps of a 45 Mbps link while TCP filled it. The cause is real Wi-Fi packet loss and quic-go's congestion control, which backs off hard, while Linux kernel TCP handles the same loss well. We had gone in half-expecting the common claim that QUIC does better on lossy links. On a real lossy link the opposite held. For plain bulk transfer on a bad link, TCP won.&lt;/p&gt;

&lt;p&gt;On its own this result argues against QUIC. We nearly stopped here.&lt;/p&gt;

&lt;h2&gt;
  
  
  Seek latency under prefetch
&lt;/h2&gt;

&lt;p&gt;An on-demand filesystem is not used by streaming a file end to end. It is used by seeking. You open a video, jump to a position, jump again. Each jump is a small read at a random offset while a prefetch pulls bulk data in the background. The number that matters is how long that small read takes while the prefetch saturates the link.&lt;/p&gt;

&lt;p&gt;On TCP, the prefetch and the seek share one byte stream, so the seek's bytes sit behind the prefetch already queued in the send buffer. That is head-of-line blocking, and it is the playback stutter we had seen before as self-congestion. On QUIC the seek gets its own stream, and the library interleaves its packets with the bulk, so it does not queue behind it.&lt;/p&gt;

&lt;p&gt;We measured it on the same Barcelona link. Thirty small 16 KB reads under a saturating bulk stream:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;p50&lt;/th&gt;
&lt;th&gt;p99&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;QUIC (seek on its own stream)&lt;/td&gt;
&lt;td&gt;109 ms&lt;/td&gt;
&lt;td&gt;322 ms&lt;/td&gt;
&lt;td&gt;387 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TCP (seek behind prefetch)&lt;/td&gt;
&lt;td&gt;3066 ms&lt;/td&gt;
&lt;td&gt;4827 ms&lt;/td&gt;
&lt;td&gt;4924 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;A seek lands in about 109 ms on QUIC, roughly one round trip. On TCP it takes about three seconds, behind the prefetch. For someone scrubbing through a video the first is usable and the second is not, and the gap is larger than the bulk-throughput gap from the previous section.&lt;/p&gt;

&lt;p&gt;This fits the earlier results together. QUIC's advantage for us is latency isolation, a seek that does not wait behind a prefetch, together with migration, a transfer that survives a network change. For an on-demand seekable filesystem that trade is worth it. TCP can match the fast lane only with a second connection per read, which is the data-channels idea we had been circling; QUIC gives it per stream, with shared congestion control.&lt;/p&gt;

&lt;h2&gt;
  
  
  What we build
&lt;/h2&gt;

&lt;p&gt;The measurements point at a specific design. The interactive on-demand path runs over QUIC. Seeks and prefetch on separate streams is where the seek result comes from, and migration comes with it. Plain bulk on a lossy link stays on TCP, where quic-go's congestion control loses. On fast, clean links the macOS syscall ceiling is real, and &lt;code&gt;sendmsg_x&lt;/code&gt; batching is the lever that lifts QUIC to about 700 MB/s while freeing CPU for the filesystem. Control traffic such as heartbeats and metadata rides QUIC, since it is small and it is the channel that has to survive a network change.&lt;/p&gt;

&lt;p&gt;None of this was obvious at the start, and several steps were the opposite of what we expected. Measuring, rather than reasoning from what QUIC is supposed to be good at, changed the answer twice: once when the slow macOS transport turned out to be a syscall cost with a fix, and once when the throughput test's verdict flipped as soon as we measured seek latency.&lt;/p&gt;

&lt;p&gt;The experiments are small and self-contained: the gRPC-over-QUIC adapter, the &lt;code&gt;sendmsg_x&lt;/code&gt; program, and the two WAN benchmarks.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Measured on a 12-core macOS laptop, a 4-core Linux VPS, and a real link between a laptop in Barcelona and the VPS at 72 ms round trip. Originally published at &lt;a href="https://keibisoft.com/blog/grpc-over-quic-seek-latency.html" rel="noopener noreferrer"&gt;keibisoft.com/blog/grpc-over-quic-seek-latency.html&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>filesystems</category>
      <category>go</category>
      <category>performance</category>
      <category>networking</category>
    </item>
    <item>
      <title>KEIBIDROP: Instant file transfer Mac to Windows</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sun, 28 Jun 2026 09:20:32 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-instant-file-transfer-mac-to-windows-3a1e</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-instant-file-transfer-mac-to-windows-3a1e</guid>
      <description>&lt;p&gt;(Left side macos, rightside windows)&lt;/p&gt;

&lt;p&gt;Work on shared files instantly.&lt;br&gt;
No more waiting for uploads or downloads.&lt;/p&gt;

&lt;p&gt;Open a 40 GB file and start working right away.&lt;br&gt;
Your edits, available instantly.&lt;/p&gt;

&lt;p&gt;This being said, this post is short, and its about the video :D&lt;/p&gt;

</description>
      <category>keibidrop</category>
      <category>go</category>
      <category>cryptography</category>
      <category>filesystems</category>
    </item>
    <item>
      <title>KEIBIDROP: Romania to Singapore Benchmarks</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sun, 14 Jun 2026 08:57:37 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-romania-to-singapore-benchmarks-5cc4</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-romania-to-singapore-benchmarks-5cc4</guid>
      <description>&lt;p&gt;Measuring an encrypted peer-to-peer filesystem over a 200 to 330 ms intercontinental link to a Windows host: throughput, connect time, and FUSE on-demand latency, and what bounds them.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Abstract.&lt;/strong&gt; Measurement of KeibiDrop, a post-quantum encrypted peer-to-peer filesystem, over a high-latency intercontinental link. Two Linux peers in Romania run against one Windows Server peer in Singapore, at 200 ms (datacenter to datacenter) and 330 ms (residential) round-trip. The Windows host is IPv4 only, so all traffic traverses the TCP bridge. Three dimensions are reported: bulk throughput, connect time, and FUSE on-demand read latency. Each cell is the median over repeated trials, with the per-table trial count n shown in the tables, all peers on commit &lt;a href="https://github.com/KeibiSoft/KeibiDrop/commit/b5a7a3e2b38efd29a963a1abf6fe1c827afec493" rel="noopener noreferrer"&gt;b5a7a3e&lt;/a&gt;. Findings: 30 to 38 MB/s into the Windows host and 13 to 25 MB/s out; connect time about 6.3 s, dominated by an IPv6 dial timeout before bridge fallback; FUSE first byte under 1.5 s with sequential on-demand read near 1 MB/s. The throughput ceiling is the bandwidth-delay product, not link capacity or CPU. FUSE mode did not start on the Windows host on this build; a fix is in review.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setup
&lt;/h2&gt;

&lt;p&gt;Three machines, two pairings. One end is always the Singapore box.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;machine&lt;/th&gt;
&lt;th&gt;details&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SG&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Singapore, Windows Server, 4 vCPU / 8 GB, WinFsp installed. IPv4 only.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;VPS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Timisoara, Linux. Also runs the relay and the TCP bridge.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;laptop&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Iasi, Linux, residential link about 500 to 600 Mbps wired (62 to 75 MB/s).&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pairing A&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;VPS to SG, about 200 ms RTT, datacenter to datacenter.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Pairing B&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;laptop to SG, about 330 ms RTT, home to datacenter.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Method:&lt;/strong&gt; each cell is the median across repeated trials, with the trial count n shown in every table: 5 at 10 and 100 MB, 3 at 1 GB, 1 at 5 and 10 GB for bulk; 10 for handshake; 3 for FUSE. All three peers run the same commit. &lt;code&gt;X to Y&lt;/code&gt; means X sends and Y receives. Bulk transfer uses &lt;code&gt;kd add&lt;/code&gt; then a timed pull, no FUSE in the path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bulk throughput
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pairing A, VPS to SG, about 200 ms&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Transfer&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;Median MB/s&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SG to VPS&lt;/td&gt;
&lt;td&gt;10 MB&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;25.6&lt;/td&gt;
&lt;td&gt;28.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS to SG&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;35.5&lt;/td&gt;
&lt;td&gt;41.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS to SG&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;37.6&lt;/td&gt;
&lt;td&gt;40.4&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG to VPS&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;13.2&lt;/td&gt;
&lt;td&gt;13.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS to SG&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;34.6&lt;/td&gt;
&lt;td&gt;34.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG to VPS&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;8.6&lt;/td&gt;
&lt;td&gt;8.6&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS to SG&lt;/td&gt;
&lt;td&gt;10 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;18.8&lt;/td&gt;
&lt;td&gt;18.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG to VPS&lt;/td&gt;
&lt;td&gt;10 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;12.9&lt;/td&gt;
&lt;td&gt;12.9&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Pairing B, laptop to SG, about 330 ms&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Transfer&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;Median MB/s&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SG to laptop&lt;/td&gt;
&lt;td&gt;10 MB&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;20.4&lt;/td&gt;
&lt;td&gt;21.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop to SG&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;5&lt;/td&gt;
&lt;td&gt;29.6&lt;/td&gt;
&lt;td&gt;30.5&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop to SG&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;29.0&lt;/td&gt;
&lt;td&gt;29.3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SG to laptop&lt;/td&gt;
&lt;td&gt;1 GB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;13.4&lt;/td&gt;
&lt;td&gt;15.1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop to SG&lt;/td&gt;
&lt;td&gt;5 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;32.9&lt;/td&gt;
&lt;td&gt;32.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop to SG&lt;/td&gt;
&lt;td&gt;10 GB&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;31.3&lt;/td&gt;
&lt;td&gt;31.3&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Handshake
&lt;/h2&gt;

&lt;p&gt;Time to connect to the Singapore box, parsed from the joiner's own log (relay lookup to connected).&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Connects to SG from&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;Median ms&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;min&lt;/th&gt;
&lt;th&gt;max&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPS (pairing A)&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;6316&lt;/td&gt;
&lt;td&gt;6473&lt;/td&gt;
&lt;td&gt;6094&lt;/td&gt;
&lt;td&gt;6476&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop (pairing B)&lt;/td&gt;
&lt;td&gt;10&lt;/td&gt;
&lt;td&gt;6220&lt;/td&gt;
&lt;td&gt;6481&lt;/td&gt;
&lt;td&gt;5977&lt;/td&gt;
&lt;td&gt;6507&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  FUSE on-demand
&lt;/h2&gt;

&lt;p&gt;A Linux peer mounts the virtual drive and reads a file hosted on SG. Content streams on demand over the link. &lt;code&gt;ttfb&lt;/code&gt; is the time to the first byte (the first 512 KB chunk). The mount is Linux because the Windows mount has a bug, covered below.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Mount reads from SG&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;n&lt;/th&gt;
&lt;th&gt;ttfb median ms&lt;/th&gt;
&lt;th&gt;p95&lt;/th&gt;
&lt;th&gt;read MB/s&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;VPS mount (pairing A)&lt;/td&gt;
&lt;td&gt;10 MB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;632&lt;/td&gt;
&lt;td&gt;1242&lt;/td&gt;
&lt;td&gt;0.9&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;VPS mount (pairing A)&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;509&lt;/td&gt;
&lt;td&gt;635&lt;/td&gt;
&lt;td&gt;1.0&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop mount (pairing B)&lt;/td&gt;
&lt;td&gt;10 MB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;709&lt;/td&gt;
&lt;td&gt;1423&lt;/td&gt;
&lt;td&gt;0.8&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;laptop mount (pairing B)&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;482&lt;/td&gt;
&lt;td&gt;549&lt;/td&gt;
&lt;td&gt;0.8&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What the numbers say
&lt;/h2&gt;

&lt;p&gt;The limit is round-trip time, not bandwidth and not CPU. The home link is 500 to 600 Mbps, which is 62 to 75 MB/s, and the best run used about half of it. The box is a 4 vCPU machine that stayed near idle, and ChaCha20 runs at gigabytes per second per core, so encryption is not the wall either. The wall is the bandwidth-delay product: one gRPC stream with a 16 MiB window cannot keep a 330 ms pipe full, because filling it needs roughly 18 MB in flight at the home link rate. A bigger window or parallel pull streams would close that gap.&lt;/p&gt;

&lt;p&gt;The Singapore box sends at about half the rate it receives. At 1 GB on pairing A it pulls in 37.6 MB/s but pushes out 13.2 MB/s, and the same shape holds across sizes and on pairing B. The receive path is fine. The send path is where the work is.&lt;/p&gt;

&lt;p&gt;The 6.3 second connect is one timeout. The box has no IPv6, so the direct IPv6 dial always fails and waits out its deadline before the bridge takes over. Skipping the direct dial when a peer advertises no IPv6 removes most of that. The same change helps phones, which are usually IPv4 only and hit the same wait.&lt;/p&gt;

&lt;p&gt;On-demand FUSE is for opening and seeking, not for streaming a whole large file. The first byte comes back in half a second to a second and a half, which is fine for opening a document, scrubbing a video, or reading part of a dataset. Sequential read settles near 1 MB/s because each 512 KB chunk costs one to three round trips at this latency. For a whole large file, a bulk pull at 30 MB/s or a prefetch is the right path.&lt;/p&gt;

&lt;h2&gt;
  
  
  Defects identified
&lt;/h2&gt;

&lt;p&gt;FUSE mode did not start on the Windows host on this build. &lt;code&gt;host.Mount&lt;/code&gt; returned false and the daemon fell back to no-FUSE: &lt;code&gt;kd list&lt;/code&gt; showed the files, but the mount point stayed an empty folder and neither local nor remote files surfaced. The cause is the mount point being created before WinFsp runs. WinFsp takes the mount point as a drive letter (for example &lt;code&gt;K:&lt;/code&gt;), an auto-assigned drive (&lt;code&gt;*&lt;/code&gt;), or a directory it creates itself, and it rejects a path that already exists. &lt;a href="https://github.com/KeibiSoft/KeibiDrop/pull/181" rel="noopener noreferrer"&gt;PR #181&lt;/a&gt; removes the pre-creation on Windows. No-FUSE transfer is unaffected, which is why the FUSE tables above use Linux mounts.&lt;/p&gt;

&lt;p&gt;One 10 GB transfer looked like it stalled at 12 MB. A re-run moved 3.7 GB in 4 minutes at a steady 15.6 MB/s, so it was a blip on the residential link, not a defect. Not filed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Planned changes
&lt;/h2&gt;

&lt;p&gt;Skip the direct dial when a peer advertises no IPv6. This removes most of the 6.3 s connect time on the common case and applies to mobile, which is also IPv4 only.&lt;/p&gt;

&lt;p&gt;Land the Windows mount fix (&lt;a href="https://github.com/KeibiSoft/KeibiDrop/pull/181" rel="noopener noreferrer"&gt;PR #181&lt;/a&gt;) so FUSE starts on the Windows host and surfaces files.&lt;/p&gt;

&lt;p&gt;Add a push-based send to remove the asymmetry where the host sends at half its receive rate.&lt;/p&gt;

&lt;p&gt;For bulk throughput, raise the window or pull with several streams. Tradeoff: saturating the link degrades on-demand read latency, so this stays opt-in for bulk transfers rather than the default for the interactive mount.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Medians over the per-table trial counts (n), all peers on commit &lt;a href="https://github.com/KeibiSoft/KeibiDrop/commit/b5a7a3e2b38efd29a963a1abf6fe1c827afec493" rel="noopener noreferrer"&gt;b5a7a3e&lt;/a&gt;. Pairing A is VPS to SG at about 200 ms. Pairing B is laptop to SG at about 330 ms. All traffic over the TCP bridge.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>filesystems</category>
      <category>network</category>
      <category>keibidrop</category>
      <category>performance</category>
    </item>
    <item>
      <title>KEIBIDROP: Also on r/selfhosted</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Mon, 01 Jun 2026 19:20:41 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-also-on-rselfhosted-2jm0</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-also-on-rselfhosted-2jm0</guid>
      <description>&lt;p&gt;I made an open source tool that allows two people to directly connect via WAN, or LAN, and mount a virtual mountpoint.&lt;/p&gt;

&lt;p&gt;(The first video in link URL shows side by side my, and my mac and brothers ubuntu use the shared mounted filesystem)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://github.com/KeibiSoft/KeibiDrop" rel="noopener noreferrer"&gt;https://github.com/KeibiSoft/KeibiDrop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The idea is that two people establish a connection, and mount virtual folders. Metadata is synced automatically when things are dragged in the virtual folder, and it supports reading with offset, which means that if Alice shares a 10GB video, or folder with files, Bob can see it in a few seconds, and start playing it.&lt;br&gt;
(Here is a fresher video where I add a Popeye 600 MB Video on my iphone, and start playing it with QuickTime and skim through it before the download completes)&lt;br&gt;
&lt;a href="https://youtu.be/UHw1WtkZ8dE" rel="noopener noreferrer"&gt;https://youtu.be/UHw1WtkZ8dE&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The tool has been in development for a little over a year, and just made it public last month.&lt;/p&gt;

&lt;p&gt;There are a series of technical blog posts about the pain points, optimization paths, and how we set benchmarks in order to make work fast at&lt;br&gt;
&lt;a href="https://keibisoft.com/blog.html#keibidrop" rel="noopener noreferrer"&gt;https://keibisoft.com/blog.html#keibidrop&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The most notable thing is that once Alice and Bob are connected they can use programs as if the filesystems were native. (thus Alice and git clone a repo, and bob git commit, or checkout instantly on the same repo).&lt;/p&gt;

&lt;p&gt;It is still in development, and as me and my brother use it and polish it we also fix any issues that arrise.&lt;/p&gt;

&lt;p&gt;Happy to discuss about it, and things that I learned while grinding on the problem :D&lt;/p&gt;

</description>
      <category>networking</category>
      <category>opensource</category>
      <category>showdev</category>
      <category>sideprojects</category>
    </item>
    <item>
      <title>KEIBIDROP: Every tool just works</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Mon, 01 Jun 2026 03:48:28 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-every-tool-just-works-1fia</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-every-tool-just-works-1fia</guid>
      <description>&lt;p&gt;We connected two machines with &lt;strong&gt;KEIBI&lt;/strong&gt;DROP and ran every program we could think of on the shared virtual folder. Compilers, version control, video processing, databases, scripting languages, security scanners. Everything worked. File integrity held across every operation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KEIBI&lt;/strong&gt;DROP presents the peer's files through the operating system's filesystem interface. Programs do not know the files are remote. They read and write to a folder. The data arrives from the other machine over an encrypted channel.&lt;/p&gt;

&lt;h2&gt;
  
  
  How the shared folder works between two machines
&lt;/h2&gt;

&lt;p&gt;Machine A adds files to the shared folder. They appear on Machine B within a second. Machine B opens them, compiles them, processes them, and saves the output back to the shared folder. Machine A sees the output immediately. No upload, no download, no sync button. Both machines read and write to the same folder in real time, over an encrypted peer-to-peer connection.&lt;/p&gt;

&lt;p&gt;We tested this with 45+ programs. Alice writes source code, Bob compiles it. Bob writes analysis results, Alice reads them. Alice has a video, Bob creates thumbnails from it. Every tool that reads files from a folder works. The programs do not know the files are on another machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;git&lt;/td&gt;
&lt;td&gt;Clone repo, run git status and git log from the other side&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;make (C)&lt;/td&gt;
&lt;td&gt;Compile 87 source files inside the shared folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;cargo (Rust)&lt;/td&gt;
&lt;td&gt;cargo build --release on the shared folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;go build&lt;/td&gt;
&lt;td&gt;Init module, build binary on the shared folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;swiftc&lt;/td&gt;
&lt;td&gt;Compile Swift program on the shared folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;xelatex&lt;/td&gt;
&lt;td&gt;Compile LaTeX slides across mounts&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Media tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ffprobe&lt;/td&gt;
&lt;td&gt;Inspect 192 MB video from peer's folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg&lt;/td&gt;
&lt;td&gt;Extract clip, create thumbnail grid from peer's video&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ImageMagick&lt;/td&gt;
&lt;td&gt;Read PNG, resize, identify 2048x5568 tileset&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Data and databases
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;SQLite&lt;/td&gt;
&lt;td&gt;Create DB on one side, JOIN query from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SQLite (multi-table)&lt;/td&gt;
&lt;td&gt;RPG save with players + inventory, JOIN from peer&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;jq&lt;/td&gt;
&lt;td&gt;Write JSON on one side, parse from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Python csv&lt;/td&gt;
&lt;td&gt;Write CSV, read with DictReader from peer&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;Write file on one side, read from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jupyter&lt;/td&gt;
&lt;td&gt;Write .ipynb on one side, parse from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Languages
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;Write module on Alice, import from Bob&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Perl&lt;/td&gt;
&lt;td&gt;SHA256 hash with Digest::SHA across mounts&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ruby&lt;/td&gt;
&lt;td&gt;JSON + Digest::MD5 across mounts&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Node.js&lt;/td&gt;
&lt;td&gt;npm install on one side, require from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bash&lt;/td&gt;
&lt;td&gt;Write script on one side, execute from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Swift&lt;/td&gt;
&lt;td&gt;Compile and run across mounts&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  File operations
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;zip / unzip&lt;/td&gt;
&lt;td&gt;Zip repo on one side, unzip on the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;tar / gzip&lt;/td&gt;
&lt;td&gt;Create archive, extract on the other side&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;rsync --checksum&lt;/td&gt;
&lt;td&gt;Checksummed copy from shared folder&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;dd&lt;/td&gt;
&lt;td&gt;1 MB + 100 MB random data, SHA256 verified both sides&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;split + cat&lt;/td&gt;
&lt;td&gt;Split file on one side, reassemble on the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;base64&lt;/td&gt;
&lt;td&gt;Encode on one side, decode on the other, hash match&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Integrity verification
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;sha256&lt;/td&gt;
&lt;td&gt;Same file hashed from both sides&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;sha512&lt;/td&gt;
&lt;td&gt;Same file hashed from both sides&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openssl dgst&lt;/td&gt;
&lt;td&gt;SHA256 digest from both sides&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;md5 (bulk)&lt;/td&gt;
&lt;td&gt;All 71 .c files hashed, aggregate compared&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;diff&lt;/td&gt;
&lt;td&gt;Source files compared across mounts&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;crc32&lt;/td&gt;
&lt;td&gt;CRC32 checksum from both sides&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Security tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;golangci-lint&lt;/td&gt;
&lt;td&gt;Lint Go source from peer's mount&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;gosec&lt;/td&gt;
&lt;td&gt;Security scan from peer's mount&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;openssl enc/dec&lt;/td&gt;
&lt;td&gt;AES-256-CBC encrypt on one side, decrypt from the other&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;exiftool&lt;/td&gt;
&lt;td&gt;Read image metadata from peer's file&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Collaborative workflows
&lt;/h2&gt;

&lt;p&gt;The shared folder is bidirectional. Both sides can write. Two people can each handle a different step of the same project.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Workflow&lt;/th&gt;
&lt;th&gt;Alice does&lt;/th&gt;
&lt;th&gt;Bob does&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;C compilation&lt;/td&gt;
&lt;td&gt;Writes main.c + headers&lt;/td&gt;
&lt;td&gt;Compiles from his view&lt;/td&gt;
&lt;td&gt;Alice runs the binary Bob built&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;LaTeX slides&lt;/td&gt;
&lt;td&gt;Writes .tex source&lt;/td&gt;
&lt;td&gt;Compiles PDF with xelatex&lt;/td&gt;
&lt;td&gt;Alice opens the PDF Bob produced&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data pipeline&lt;/td&gt;
&lt;td&gt;Writes 100-row CSV&lt;/td&gt;
&lt;td&gt;Runs Python analysis, writes JSON&lt;/td&gt;
&lt;td&gt;Alice reads Bob's results&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Video processing&lt;/td&gt;
&lt;td&gt;Has a 190 MB video&lt;/td&gt;
&lt;td&gt;Creates thumbnail grid with ffmpeg&lt;/td&gt;
&lt;td&gt;Alice sees the thumbnails&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Large files
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Test&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;100 MB random file, SHA256 from both sides&lt;/td&gt;
&lt;td&gt;100 MB&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;192 MB video, ffprobe from peer's mount&lt;/td&gt;
&lt;td&gt;192 MB&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ffmpeg transcode: Bob processes Alice's video, output appears on Alice&lt;/td&gt;
&lt;td&gt;192 MB in, 153 KB out&lt;/td&gt;
&lt;td&gt;Works&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;50 files written by Alice, aggregate hash verified by Bob&lt;/td&gt;
&lt;td&gt;50 files&lt;/td&gt;
&lt;td&gt;Identical&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;71 source files tar'd, extracted on other side, all hashes verified&lt;/td&gt;
&lt;td&gt;71 files&lt;/td&gt;
&lt;td&gt;All match&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What does not work
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Reason&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Symlinks / hardlinks&lt;/td&gt;
&lt;td&gt;Not implemented. Tools like uv, npm with bin links fail. Use --no-bin-links or install outside the shared folder.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Execute binaries from mount (macOS)&lt;/td&gt;
&lt;td&gt;macOS blocks execution from FUSE mounts. Copy the binary locally first. Linux does not have this restriction.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How it works
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;KEIBI&lt;/strong&gt;DROP presents the peer's files through the OS filesystem interface (FUSE on macOS/Linux, WinFsp on Windows). Every program that reads files through standard system calls works without modification. The file metadata syncs when the connection establishes. File contents stream on demand as programs read them. The encryption overhead is under 2%.&lt;/p&gt;

&lt;p&gt;The connection is end-to-end encrypted with post-quantum cryptography (ML-KEM-1024 + X25519). No server stores your files.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Install: &lt;a href="https://keibidrop.com/install.html" rel="noopener noreferrer"&gt;keibidrop.com/install&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Source: &lt;a href="https://github.com/KeibiSoft/KeibiDrop" rel="noopener noreferrer"&gt;github.com/KeibiSoft/KeibiDrop&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>opensource</category>
      <category>linux</category>
      <category>devops</category>
      <category>security</category>
    </item>
    <item>
      <title>KeibiDrop: Instant share 600 MB video from phone to Destkop</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sat, 30 May 2026 18:07:51 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-instant-share-600-mb-video-from-phone-to-destkop-3i3b</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-instant-share-600-mb-video-from-phone-to-destkop-3i3b</guid>
      <description>&lt;p&gt;Here I add a 600MB Popeye video from my iPhone and can open it instantly on my desktop and jump through it, while the downloads happen in the background.&lt;/p&gt;

&lt;p&gt;It works with all types of files and programs, including git clone.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keibidrop.com" rel="noopener noreferrer"&gt;https://keibidrop.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;and on &lt;a href="https://github.com/KeibiSoft/KeibiDrop/" rel="noopener noreferrer"&gt;github:&lt;/a&gt;&lt;/p&gt;

</description>
      <category>opensource</category>
      <category>showdev</category>
      <category>sideprojects</category>
      <category>tooling</category>
    </item>
    <item>
      <title>Mobile apps coming soon!</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Sat, 09 May 2026 15:41:01 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/mobile-apps-coming-soon-3gf0</link>
      <guid>https://dev.to/mfc_keibisoft/mobile-apps-coming-soon-3gf0</guid>
      <description>&lt;div class="ltag__link--embedded"&gt;
  &lt;div class="crayons-story "&gt;
  &lt;a href="https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n" class="crayons-story__hidden-navigation-link"&gt;KEIBIDROP: Secure File Transfer!&lt;/a&gt;


  &lt;div class="crayons-story__body crayons-story__body-full_post"&gt;
    &lt;div class="crayons-story__top"&gt;
      &lt;div class="crayons-story__meta"&gt;
        &lt;div class="crayons-story__author-pic"&gt;

          &lt;a href="/mfc_keibisoft" class="crayons-avatar  crayons-avatar--l  "&gt;
            &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3844364%2F3d4c1171-f666-46a9-81b9-157ec5f41c94.jpeg" alt="mfc_keibisoft profile" class="crayons-avatar__image" width="800" height="799"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
        &lt;div&gt;
          &lt;div&gt;
            &lt;a href="/mfc_keibisoft" class="crayons-story__secondary fw-medium m:hidden"&gt;
              Marius-Florin Cristian
            &lt;/a&gt;
            &lt;div class="profile-preview-card relative mb-4 s:mb-0 fw-medium hidden m:inline-block"&gt;
              
                Marius-Florin Cristian
                
              
              &lt;div id="story-author-preview-content-3558201" class="profile-preview-card__content crayons-dropdown branded-7 p-4 pt-0"&gt;
                &lt;div class="gap-4 grid"&gt;
                  &lt;div class="-mt-4"&gt;
                    &lt;a href="/mfc_keibisoft" class="flex"&gt;
                      &lt;span class="crayons-avatar crayons-avatar--xl mr-2 shrink-0"&gt;
                        &lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3844364%2F3d4c1171-f666-46a9-81b9-157ec5f41c94.jpeg" class="crayons-avatar__image" alt="" width="800" height="799"&gt;
                      &lt;/span&gt;
                      &lt;span class="crayons-link crayons-subtitle-2 mt-5"&gt;Marius-Florin Cristian&lt;/span&gt;
                    &lt;/a&gt;
                  &lt;/div&gt;
                  &lt;div class="print-hidden"&gt;
                    
                      Follow
                    
                  &lt;/div&gt;
                  &lt;div class="author-preview-metadata-container"&gt;&lt;/div&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;

          &lt;/div&gt;
          &lt;a href="https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n" class="crayons-story__tertiary fs-xs"&gt;&lt;time&gt;Apr 27&lt;/time&gt;&lt;span class="time-ago-indicator-initial-placeholder"&gt;&lt;/span&gt;&lt;/a&gt;
        &lt;/div&gt;
      &lt;/div&gt;

    &lt;/div&gt;

    &lt;div class="crayons-story__indention"&gt;
      &lt;h2 class="crayons-story__title crayons-story__title-full_post"&gt;
        &lt;a href="https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n" id="article-link-3558201"&gt;
          KEIBIDROP: Secure File Transfer!
        &lt;/a&gt;
      &lt;/h2&gt;
        &lt;div class="crayons-story__tags"&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/go"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;go&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/security"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;security&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/filesystem"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;filesystem&lt;/a&gt;
            &lt;a class="crayons-tag  crayons-tag--monochrome " href="/t/rust"&gt;&lt;span class="crayons-tag__prefix"&gt;#&lt;/span&gt;rust&lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="crayons-story__bottom"&gt;
        &lt;div class="crayons-story__details"&gt;
            &lt;a href="https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n#comments" class="crayons-btn crayons-btn--s crayons-btn--ghost crayons-btn--icon-left flex items-center"&gt;
              

              &lt;span class="hidden s:inline"&gt;Add&amp;nbsp;Comment&lt;/span&gt;
            &lt;/a&gt;
        &lt;/div&gt;
        &lt;div class="crayons-story__save"&gt;
          &lt;small class="crayons-story__tertiary fs-xs mr-2"&gt;
            1 min read
          &lt;/small&gt;
            
              &lt;span class="bm-initial"&gt;
                

              &lt;/span&gt;
              &lt;span class="bm-success"&gt;
                

              &lt;/span&gt;
            
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
  &lt;/div&gt;
&lt;/div&gt;

&lt;/div&gt;


</description>
    </item>
    <item>
      <title>KEIBIDROP: Secure File Transfer!</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Mon, 27 Apr 2026 15:30:09 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-secure-file-transfer-132n</guid>
      <description>&lt;p&gt;&lt;strong&gt;KEIBI&lt;/strong&gt;DROP encrypted file transfer and shared filesystem between two devices&lt;/p&gt;

&lt;p&gt;&lt;a href="https://keibidrop.com" rel="noopener noreferrer"&gt;https://keibidrop.com&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;KeibiDrop connects two devices directly and lets them share files over an encrypted channel. It works over the internet or a local network.&lt;/p&gt;

&lt;p&gt;Two modes:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Direct transfer&lt;/strong&gt; - drag files in, your peer saves what they need&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Virtual folder (FUSE)&lt;/strong&gt; - your peer's files appear as a real folder on your machine. git, rsync, your IDE, all work on it. Files stream on access, so you can open a 4 GB video before it finishes downloading.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Post-quantum encryption (ML-KEM-1024 + X25519). The relay, if used, cannot decrypt anything.&lt;/p&gt;

&lt;p&gt;macOS, Windows, Linux. Desktop GUI, interactive CLI, agent CLI for automation.&lt;/p&gt;

&lt;p&gt;Free, open source (MPL-2.0): &lt;a href="https://github.com/KeibiSoft/KeibiDrop" rel="noopener noreferrer"&gt;github.com/KeibiSoft/KeibiDrop&lt;/a&gt;&lt;/p&gt;

</description>
      <category>go</category>
      <category>security</category>
      <category>filesystem</category>
      <category>rust</category>
    </item>
    <item>
      <title>KEIBIDROP v0.1.0 is out! https://github.com/KeibiSoft/KeibiDrop/releases/tag/v0.1.0

Now you can send files, or mount files in real time as a distributed system :D 
Direct peer to peer or fallback via datarelay.
Open source, and no transfer limits!</title>
      <dc:creator>Marius-Florin Cristian</dc:creator>
      <pubDate>Mon, 27 Apr 2026 09:59:44 +0000</pubDate>
      <link>https://dev.to/mfc_keibisoft/keibidrop-v010-is-out-httpsgithubcomkeibisoftkeibidropreleasestagv010-now-you-can-3ea8</link>
      <guid>https://dev.to/mfc_keibisoft/keibidrop-v010-is-out-httpsgithubcomkeibisoftkeibidropreleasestagv010-now-you-can-3ea8</guid>
      <description>&lt;div class="crayons-card c-embed text-styles text-styles--secondary"&gt;
    &lt;div class="c-embed__content"&gt;
        &lt;div class="c-embed__cover"&gt;
          &lt;a href="https://github.com/KeibiSoft/KeibiDrop/releases/tag/v0.1.0" class="c-link align-middle" rel="noopener noreferrer"&gt;
            &lt;img alt="" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fopengraph.githubassets.com%2Ff5c68af7c9589f25f7f61e140cf5e75862521b00f5ceb4a6b75ca5da43bc8f2a%2FKeibiSoft%2FKeibiDrop%2Freleases%2Ftag%2Fv0.1.0" height="400" class="m-0" width="800"&gt;
          &lt;/a&gt;
        &lt;/div&gt;
      &lt;div class="c-embed__body"&gt;
        &lt;h2 class="fs-xl lh-tight"&gt;
          &lt;a href="https://github.com/KeibiSoft/KeibiDrop/releases/tag/v0.1.0" rel="noopener noreferrer" class="c-link"&gt;
            Release KeibiDrop v0.1.0 · KeibiSoft/KeibiDrop · GitHub
          &lt;/a&gt;
        &lt;/h2&gt;
          &lt;p class="truncate-at-3"&gt;
            First public release. Peer-to-peer encrypted file sharing across Linux, macOS, and Windows.
What's in this release

End-to-end encrypted transfer (AES-256-GCM / ChaCha20-Poly1305, auto-negotiated b...
          &lt;/p&gt;
        &lt;div class="color-secondary fs-s flex items-center"&gt;
            &lt;img alt="favicon" class="c-embed__favicon m-0 mr-2 radius-0" src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.githubassets.com%2Ffavicons%2Ffavicon.svg" width="32" height="32"&gt;
          github.com
        &lt;/div&gt;
      &lt;/div&gt;
    &lt;/div&gt;
&lt;/div&gt;


</description>
    </item>
  </channel>
</rss>
