<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
 
 <title>Bluish Coder: freenet</title>
 <link href="http://bluishcoder.co.nz/tag/freenet/atom.xml" rel="self"/>
 <link href="http://bluishcoder.co.nz/"/>
 <updated>2018-12-17T08:49:52+13:00</updated>
 <id>http://bluishcoder.co.nz/</id>
 <author>
   <name>Bluishcoder</name>
   <email>admin@bluishcoder.co.nz</email>
 </author>

 
 <entry>
   <title>Distributed Wikipedia Mirrors in Freenet</title>
   <link href="http://bluishcoder.co.nz/2017/05/16/distributed-wikipedia-mirrors-in-freenet.html"/>
   <updated>2017-05-16T17:00:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2017/05/16/distributed-wikipedia-mirrors-in-freenet</id>
   <content type="html">&lt;p&gt;There was a recent post about &lt;a href=&quot;https://ipfs.io/blog/24-uncensorable-wikipedia/&quot;&gt;uncensorable Wikipedia mirrors on IPFS&lt;/a&gt;. The IPFS project put a snapshot of the Turkish version of Wikipedia on IPFS. This is a great idea and something I&#39;ve wanted to try on &lt;a href=&quot;http://freenetproject.org/&quot;&gt;Freenet&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://freenetproject.org/&quot;&gt;Freenet&lt;/a&gt;  is an anonymous, secure, distributed datastore that I&#39;ve written &lt;a href=&quot;http://bluishcoder.co.nz/tags/freenet/index.html&quot;&gt;a few posts about&lt;/a&gt;. It wasn&#39;t too difficult to convert the IPFS process to something that worked on Freenet. For the Freenet keys linked in this post I&#39;m using a proxy that retrieves data directly from Freenet. This uses the &lt;a href=&quot;https://github.com/saces/SCGIPublisher&quot;&gt;SCGIPublisher plugin&lt;/a&gt; on a local Freenet node. The list of whitelisted keys usable are at &lt;a href=&quot;https://freenet.cd.pn/&quot;&gt;freenet.cd.pn&lt;/a&gt;. There is also a gateway available at &lt;a href=&quot;https://d6.gnutella2.info/freenet&quot;&gt;d6.gnutella2.info&lt;/a&gt;. The keys can also be used directly from a Freenet node, which is likely to be more performant than going through my underpowered proxy. Keep in mind that the &quot;distributed, can&#39;t be taken down&quot; aspect of the sites on Freenet is only when accessed directly through Freenet. It&#39;s quite likely my clearnet proxy won&#39;t be able to handle large amounts of traffic.&lt;/p&gt;

&lt;p&gt;I started with the &lt;a href=&quot;https://freenet.cd.pn/USK@HdWqD7afIfjYuqqE74kJDwhYa2eetoPL7cX4TRHtZwc,CeRayXsCZR6qYq5tDmG6r24LrEgaZT9L2iirqa9tIgc,AQACAAE/pitkern-wikipedia/2/&quot;&gt;Pitkern/Norfuk Wikipedia Snapshot&lt;/a&gt; as that was relatively small. Once I got the scripts for that working I converted the &lt;a href=&quot;https://freenet.cd.pn/USK@jYBa5KmwybC9mQ2QJEuuQhCx9VMr9bb3ul7w1TnyVwE,OMqNMLprCO6ostkdK6oIuL1CxaI3PFNpnHxDZClGCGU,AQACAAE/maori-wikipedia/6/&quot;&gt;Māori Wikipedia Snapshot&lt;/a&gt;. The lastest test I did was the &lt;a href=&quot;https://freenet.cd.pn/USK@m79AuzYDr-PLZ9kVaRhrgza45joVCrQmU9Er7ikdeRI,1mtRcpsTNBiIHOtPRLiJKDb1Al4sJn4ulKcZC5qHrFQ,AQACAAE/simple-wikipedia/0/&quot;&gt;Simple English Wikipedia Snapshot&lt;/a&gt;. This was much bigger so I did the version without images first. Later I plan to try the version with images when I&#39;ve resolved some issues with the current process.&lt;/p&gt;

&lt;p&gt;The Freenet keys for these mirrors are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;small&gt;USK@m79AuzYDr-PLZ9kVaRhrgza45joVCrQmU9Er7ikdeRI,1mtRcpsTNBiIHOtPRLiJKDb1Al4sJn4ulKcZC5qHrFQ,AQACAAE/simple-wikipedia/0/&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;&lt;small&gt;USK@jYBa5KmwybC9mQ2QJEuuQhCx9VMr9bb3ul7w1TnyVwE,OMqNMLprCO6ostkdK6oIuL1CxaI3PFNpnHxDZClGCGU,AQACAAE/maori-wikipedia/5/&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;&lt;small&gt;USK@HdWqD7afIfjYuqqE74kJDwhYa2eetoPL7cX4TRHtZwc,CeRayXsCZR6qYq5tDmG6r24LrEgaZT9L2iirqa9tIgc,AQACAAE/pitkern-wikipedia/2/&lt;/small&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The keys are &#39;USK&#39; keys. These keys can be updated and have an edition number at the end of them. This number will increase as newer versions of the mirrors are pushed out. The Freenet node will often find the latest edition it knows about, or the latest edition can be searched for using &#39;-1&#39; as the edition number.&lt;/p&gt;

&lt;p&gt;The approach I took for the mirroring follows the approach IPFS took. I used the ZIM archives provided by &lt;a href=&quot;http://wiki.kiwix.org/wiki/Content_in_all_languages&quot;&gt;Kiwix&lt;/a&gt; and a &lt;a href=&quot;https://github.com/dignifiedquire/zim&quot;&gt;ZIM extractor&lt;/a&gt; written in Rust. The archive was extracted with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ extract_zim wikipedia_en_simple_all_nopic.zim
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This places the content in an &lt;code&gt;out&lt;/code&gt; directory. All HTML files are stored in a single directory, &lt;code&gt;out/A&lt;/code&gt;. In the &#39;simple english&#39; case that&#39;s over 170,000 files. This is too many files in a directory for Freenet to insert. I wrote a script in bash to split the directory so that files are stored in &#39;000/filename.html&#39; where &#39;000&#39; is the first three digits of a SHA256 hash of the base filename, computed with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ echo &quot;filename.html&quot;|sha256sum|awk &#39;{ print $1 }&#39;|cut -c &quot;1,2,3&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The script then went through and adjusted the article and image links on each page to point to the new location. The script does some other things to remove HTML tags that the Freenet HTML filter doesn&#39;t like and to add a footer about the origin of the mirror.&lt;/p&gt;

&lt;p&gt;Another issue I faced was that filenames with non-ascii characters would get handled differently by Freenet if the file was inserted as a single file vs being inserted as part of a directory. In the later case the file could not be retrieved later. I worked around this by translating filenames into ascii. A more robust solution would be needed here if I can&#39;t track down where the issue is occurring.&lt;/p&gt;

&lt;p&gt;This script to do the conversion is in my &lt;a href=&quot;https://github.com/doublec/freenet-wikipedia&quot;&gt;freenet-wikipedia&lt;/a&gt; githib repository. To convert a ZIM archive the steps are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ wget http://download.kiwix.org/zim/wikipedia_pih_all.zim
$ extract_zim wikipedia_pih_all.zim
$ ./convert.sh
$ ./putdir.sh result my-mirror index.html
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;At completion of the insert this will output a list of keys. the &lt;code&gt;uri&lt;/code&gt; key is the one that can be shared for others to retrieve the insert. The &lt;code&gt;uskinsert&lt;/code&gt; key can be used to insert an updated version of the site:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./putdir.sh result my-mirror index.html &amp;lt;uskinsert key&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;convert.sh&lt;/code&gt; script was a quick &#39;proof of concept&#39; hack and could be improved in many ways. It is also very slow. It took about 24 hours to do the simple english conversion. I welcome patches and better ways of doing things.&lt;/p&gt;

&lt;p&gt;The repository includes a bash script, &lt;code&gt;putdir.sh&lt;/code&gt;, which will insert the site using the Freenet &lt;code&gt;ClientPutDiskDir&lt;/code&gt; API message. This is a useful way to get a directory online quickly but is not an optimal way of inserting something the size of the mirror. The initial request for the site downloads a manifest containing a list of all the files in the site. This can be quite large. It&#39;s 12MB for the Simple English mirror with no images. For the Māori mirror it&#39;s almost 50MB due to the images. The layout of the files doesn&#39;t take into account likely retrieval patterns. So images and scripts that are included in a page are not downloaded as part of the initial page request, but may result in pulling in larger amounts of data depending on how that file was inserted. A good optimisation project would be to analyse the directory to be inserted and create an optimal Freenet insert for faster retrieval. &lt;a href=&quot;https://github.com/freenet/pyFreenet&quot;&gt;pyFreenet&lt;/a&gt; has a utility, &lt;code&gt;freesitemgr&lt;/code&gt;, that can do some of this and there are other insertion tools like &lt;a href=&quot;https://github.com/Bombe/jSite&quot;&gt;jSite&lt;/a&gt; that may also do a better job.&lt;/p&gt;

&lt;p&gt;My goal was to do a proof of concept to see if a Wikipedia mirror on Freenet was viable. This seems to be the case and the Simple English mirror is very usable. Discussion on the &lt;a href=&quot;http://freesocial.draketo.de/fms_en.html&quot;&gt;FMS&lt;/a&gt; forum when I announced the site has been positive. I hope to improve the process over time and welcome any suggestions or enhancements to do that.&lt;/p&gt;

&lt;p&gt;What are the differences between this and the IPFS mirror? It&#39;s mostly down to how IPFS and Freenet work.&lt;/p&gt;

&lt;p&gt;In Freenet content is distributed across all nodes in the network. The node that has inserted the data can turn their node off and the content remains in the network. No single node has all the content. There is redundancy built in so if nodes go offline the content can still be fully retrieved. Node space is limited so as data is inserted into Freenet, data that is not requested often is lost to make room. This means that content that is not popular disappears over time. I suspect this means that some of the wikipedia pages will become inaccessible. This can be fixed by periodically reinserting the content, healing the specific missing content, or using the &lt;code&gt;KeepAlive&lt;/code&gt; plugin to keep content around. Freenet is encrypted and anonymous. You can browse Wikipedia pages without an attacker knowing that you are doing so. Your node doesn&#39;t share the Wikipedia data, except possibly small encrypted chunks of parts of it in your datastore, and it&#39;s difficult for the attacker to identify you as a sharer of that data. The tradeoff of this security is retrievals are slower.&lt;/p&gt;

&lt;p&gt;In IPFS a node inserting the content cannot be turned off until that content is pinned by another node on the network and fully retrieved. Nodes that pin the content keep the entire content on their node. If all pinned nodes go offline then the content is lost. All nodes sharing the content advertise that fact. It&#39;s easy to obtain the IP address of all nodes that are sharing Wikipedia files. On the positive side IPFS is potentially quite a bit faster to retrieve data.&lt;/p&gt;

&lt;p&gt;Both IPFS and Freenet have interesting use cases and tradeoffs. The intent of this experiment is not to present one or the other as a better choice, but to highlight what Freenet can do and make the content available within the Freenet network.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Introduction to the Freenet API</title>
   <link href="http://bluishcoder.co.nz/2017/03/28/introduction-to-the-freenet-api.html"/>
   <updated>2017-03-28T17:00:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2017/03/28/introduction-to-the-freenet-api</id>
   <content type="html">&lt;p&gt;&lt;a href=&quot;https://freenetproject.org/&quot;&gt;Freenet&lt;/a&gt;  is an anonymous, secure, distributed datastore. I&#39;ve written about &lt;a href=&quot;http://bluishcoder.co.nz/2014/12/18/using-freenet.html&quot;&gt;using Freenet&lt;/a&gt; before, including using it as the &lt;a href=&quot;http://bluishcoder.co.nz/2015/09/14/using-freenet-for-static-websites.html&quot;&gt;backend for static websites&lt;/a&gt;. In this post I&#39;ll demonstrate how to use the Freenet API to push data into the Freenet network and retrieve data from it.&lt;/p&gt;

&lt;p&gt;Unfortunately the freenet protocol documentation is in a state of flux as it moves from a previous wiki to a github based wiki. This means some of the protocol information may be incomplete. The old wiki data is stored in Freenet under the following keys:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;small&gt;CHK@San0hXZSyCEvvb7enNUIWrkiv8MDChn8peLJllnWt4s,MCNn4eUbl5NW9quOm4JTU~0rsWu6QlIdek9VtpFpXe4,AAMC--8/freenetproject-oldwiki.tar&lt;/small&gt;&lt;/li&gt;
&lt;li&gt;&lt;small&gt;CHK@4sff2MgvexbsfgSuqNOwqVDkP~GaZPsZ1rJVKUg87g8,unU3TZ93pYGYPCoH7LC53dlc5~Rmar8SKF9fsZnQX-8,AAMC--8/freenetproject-wiki.tar&lt;/small&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The API for external programs to communicate with a running Freenet daemon is &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2&quot;&gt;FCPv2&lt;/a&gt;. It&#39;s a text based protocol accessed using a TCP socket connection on port 9481. The FCP protocol can be enabled or disabled from the Freenet configuration settings but it is enabled by default so the examples here should work in a default installation.&lt;/p&gt;

&lt;p&gt;The basic protocol of FCP uses a unit called a &#39;message&#39;. Messages are sent over the socket starting with a line for the start of the message, followed by a series of &#39;Key=Value&#39; lines, and ending the message with &#39;EndMessage&#39;. Some messages containing binary data and these end differently and I&#39;ll discuss this after some basic examples.&lt;/p&gt;

&lt;p&gt;For the examples that follow I&#39;ll be using &lt;a href=&quot;https://www.gnu.org/software/bash/&quot;&gt;bash&lt;/a&gt;. I debated picking from my usual toolkit of obscure languages but decided to use something that doesn&#39;t require installation on Linux and Mac OS X and may also run on &lt;a href=&quot;https://msdn.microsoft.com/en-us/commandline/wsl/about&quot;&gt;Windows 10&lt;/a&gt;. The examples should be readable enough for non-bash users to pick up and translate to their favourite language, especially given the simplicity of the protocol. I&#39;ve found the ability to throw together a quick bash script to do inserts and retrievals to be useful.&lt;/p&gt;

&lt;h2&gt;Hello&lt;/h2&gt;

&lt;p&gt;The &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2&quot;&gt;FCPv2 documentation&lt;/a&gt; lists the messages that can be sent from the client to the Freenet node, and what can be expected to be received from the node to the client. On first connecting to the node the client must send a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-ClientHello&quot;&gt;ClientHello&lt;/a&gt; message. This looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ClientHello
Name=My Client Name
ExpectedVersion=2.0
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;Name&lt;/code&gt; field uniquely identifies the client to the node. Disconnecting and reconnecting with the same &lt;code&gt;Name&lt;/code&gt; retains access to a persistent queue of data being inserted and retrieved. An error is returned if an attempt to connect is made when a client with the same &lt;code&gt;Name&lt;/code&gt; is already connected.&lt;/p&gt;

&lt;p&gt;The node returns with a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-NodeHello&quot;&gt;NodeHello&lt;/a&gt; Message. This looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;NodeHello
Build=1477
ConnectionIdentifier=...
...
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The various fields are described in the &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-NodeHello&quot;&gt;NodeHello documentation&lt;/a&gt;. This interaction can be tested using &lt;code&gt;netcat&lt;/code&gt; or &lt;code&gt;telnet&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ nc localhost 9481
ClientHello
Name=My Client Name
ExpectedVersion=2.0
EndMessage

NodeHello
CompressionCodecs=4 - GZIP(0), BZIP2(1), LZMA(2), LZMA_NEW(3)
Revision=build01477
Testnet=false
...
ExtRevision=v29
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;You can connect to a socket from bash using &#39;exec&#39; and file redirection to a pseudo-path describing the tcp socket. See &lt;a href=&quot;http://hacktux.com/bash/socket&quot;&gt;HACKTUX notes from the trenches&lt;/a&gt; for details. The above netcat interaction looks like this from bash:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;&lt;span class=&quot;c&quot;&gt;#! /bin/bash&lt;/span&gt;
    &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;wait_for &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;line
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;str&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;$1&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; -r line
      &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
        &amp;gt;&amp;amp;2 &lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt;
        &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$str&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;      done&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
       
    &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;3&amp;lt;&amp;gt;/dev/tcp/127.0.0.1/9481
       
    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientHello&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Name=My Client Name&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ExpectedVersion=2.0&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
       
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;NodeHello&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
       
    &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;3&amp;lt;&amp;amp;-
    &lt;span class=&quot;nb&quot;&gt;exec &lt;/span&gt;3&amp;gt;&amp;amp;-
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;exec&lt;/code&gt; line opens a socket on port 9481, the FCP port, and assigns it to file descriptor &#39;3&#39;. Then we use &lt;code&gt;cat&lt;/code&gt; to write the &lt;code&gt;ClientHello&lt;/code&gt; message to that file descriptor. &lt;code&gt;wait_for&lt;/code&gt; reads lines from the socket, displaying them on standard error (file descriptor &#39;2&#39;), until it reaches a specifc line passed as an argument. Here we wait for the &lt;code&gt;NodeHello&lt;/code&gt; line and then the &lt;code&gt;EndMesage&lt;/code&gt; line to cover the &lt;code&gt;NodeHello&lt;/code&gt; response from the server. The remaining two &lt;code&gt;exec&lt;/code&gt; lines close the socket.&lt;/p&gt;

&lt;p&gt;The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/hello.sh&quot;&gt;hello.sh&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Retrieving data inline&lt;/h2&gt;

&lt;p&gt;The FCP message &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-ClientGet&quot;&gt;ClientGet&lt;/a&gt; is used to retrieve data stored at a specific key. The data can be returned inline within a message or written to a file accessable by the node. An example message for retrieving a known key is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ClientGet
URI=CHK@otFYYKhLKFzkAKhEHWPzVAbzK9F3BRxLwuoLwkzefqA,AKn6KQE7c~8G5dLa4TuyfG16XIUwycWuFurNJYjbXu0,AAMC--8/example.txt
Identifier=1234
Verbosity=0
ReturnType=direct
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This retrieves the contents of a particular &lt;code&gt;CHK&lt;/code&gt; key where I stored &lt;code&gt;example.txt&lt;/code&gt;. The &lt;code&gt;Verbosity&lt;/code&gt; is set to not return any progress messages, just send messages when the entire contents are retrieved. A &lt;code&gt;ReturnType&lt;/code&gt; of &lt;code&gt;direct&lt;/code&gt; means return the data within the &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-AllData&quot;&gt;AllData&lt;/a&gt; message which is received when the retrieval is complete. The result messages are:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;DataFound
Identifier=1234
CompletionTime=1490614072644
StartupTime=1490614072634
DataLength=21
Global=false
Metadata.ContentType=text/plain
EndMessage

AllData
Identifier=1234
CompletionTime=1490614072644
StartupTime=1490614072634
DataLength=21
Global=false
Metadata.ContentType=text/plain
Data
Hello Freenet World!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The first message received is &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-DataFound&quot;&gt;DataFound&lt;/a&gt; giving information about the completed request. The following message, &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-AllData&quot;&gt;AllData&lt;/a&gt;, returns the actual data. Note that it does not include an &lt;code&gt;EndMessage&lt;/code&gt;. Instead it has a &lt;code&gt;Data&lt;/code&gt; terminator followed by the data as a sequence of bytes of length &lt;code&gt;DataLength&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;To process &lt;code&gt;AllData&lt;/code&gt; from bash I use a function to extract the &lt;code&gt;DataLength&lt;/code&gt; when it finds it:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;get_data_length &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;line
      &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; -r line
      &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^DataLength&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##DataLength=}&amp;quot;&lt;/span&gt;
         &lt;span class=&quot;nb&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;      done&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This is called from the script after the &lt;code&gt;ClientHello&lt;/code&gt; and &lt;code&gt;NodeHello&lt;/code&gt; exchange:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientGet&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    URI=CHK@otFYYKhLKFzkAKhEHWPzVAbzK9F3BRxLwuoLwkzefqA,AKn6KQE7c~8G5dLa4TuyfG16XIUwycWuFurNJYjbXu0,AAMC--8/example.txt&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Identifier=1234&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Verbosity=0&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ReturnType=direct&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
        
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;AllData&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    &lt;span class=&quot;nv&quot;&gt;len&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_data_length &amp;lt;&amp;amp;3&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;Data&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    dd &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;none &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$len&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 &amp;lt;&amp;amp;3 &amp;gt;&amp;amp;2
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;dd&lt;/code&gt; command reads the specified number of bytes from the socket and outputs it to standard output. This is the contents of the key we requested:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ./getinline
Hello Freenet World!
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/getinline.sh&quot;&gt;getinline.sh&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The main downside of using inline data requests is that large files can exhaust the memory of the node.&lt;/p&gt;

&lt;h2&gt;Request Direct Disk Access&lt;/h2&gt;

&lt;p&gt;A variant of &lt;code&gt;ClientGet&lt;/code&gt; requests the node to write the result to a file on disk instead of sending it as part of the &lt;code&gt;AllData&lt;/code&gt; message. This is useful for large files that don&#39;t fit in memory. The data is written to the filesystem that the node has access to so it&#39;s most useful when the FCP client and the freenet node are on the same system.&lt;/p&gt;

&lt;p&gt;Being able to tell the server to write directly to the filesystem is a security issue so Freenet requires a negotiation to happen first to confirm that the client has access to the directory that you are requesting the server to write to. This negotiation requirement, known as &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-TestDDARequest&quot;&gt;TestDDA&lt;/a&gt; can be disabled in the configuration settings of the node but it&#39;s not recommended.&lt;/p&gt;

&lt;p&gt;First the client must send a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-TestDDARequest&quot;&gt;TestDDARequest&lt;/a&gt; message listing the directory it wants access to and whether read or write access is being requested.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TestDDARequest
Directory=/tmp/
WantWriteDirectory=true
WantReadDirectory=true
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The server replies with a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-TestDDAReply&quot;&gt;TestDDAReply&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TestDDAReply
Directory=/tmp/
ReadFilename=/tmp/testr.tmp
WriteFilename=/tmp/testw.tmp
ContentToWrite=RANDOM
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The script should now write the data contained in the &lt;code&gt;ContentToWrite&lt;/code&gt; key into the file referenced by the &lt;code&gt;WriteFilename&lt;/code&gt; key. It should read the data from the file referenced in the &lt;code&gt;ReadFilename&lt;/code&gt; key and send that data in a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-TestDDAResponse&quot;&gt;TestDDAResponse&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TestDDAResponse
Directory=/tmp/
ReadContent=...content from TestDDAReply...
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The server then responds with a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-TestDDAComplete&quot;&gt;TestDDAComplete&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;TestDDAComplete
Directory=/tmp/
ReadDirectoryAllowed=true
WriteDirectoryAllowed=true
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once that dance is complete then put and get requests can be done to that specific directory. The bash code for doing this is:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    TestDDARequest&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Directory=/tmp/&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    WantWriteDirectory=true&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    WantReadDirectory=true&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
    
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;TestDDAReply&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    &lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;process_dda_reply &amp;lt;&amp;amp;3&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    
    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    TestDDAResponse&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Directory=/tmp/&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ReadContent=$content&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
    
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;TestDDAComplete&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    process_dda_complete &amp;lt;&amp;amp;3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;It uses a helper function &lt;code&gt;process_dda_reply&lt;/code&gt; to handle the &lt;code&gt;TestDDAReply&lt;/code&gt; message from the server:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;process_dda_reply &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;readfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;writefile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; -r line
      &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^ReadFilename&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;readfile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##ReadFilename=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^WriteFilename&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;writefile&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##WriteFilename=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^ContentToWrite&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;content&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##ContentToWrite=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; -n &lt;span class=&quot;s2&quot;&gt;&amp;quot;$content&amp;quot;&lt;/span&gt; &amp;gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$writefile&amp;quot;&lt;/span&gt;
         cat &lt;span class=&quot;s2&quot;&gt;&amp;quot;$readfile&amp;quot;&lt;/span&gt;
         &lt;span class=&quot;nb&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;      done&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;This function reads the fields of the &lt;code&gt;TestDDAReply&lt;/code&gt; and writes the required content to the write file and returns the data contained in the read file. This returned data is sent in the &lt;code&gt;TestDDAResponse&lt;/code&gt;. The &lt;code&gt;process_dda_complete&lt;/code&gt; function checks the &lt;code&gt;TestDDAComplete&lt;/code&gt; fields to ensure that access was granted. The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/testdda.sh&quot;&gt;testdda.sh&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Retrieving data to disk&lt;/h2&gt;

&lt;p&gt;The &lt;code&gt;ReturnType&lt;/code&gt; field of the &lt;code&gt;ClientGet&lt;/code&gt; message can be set to &lt;code&gt;disk&lt;/code&gt; to write directly to a disk file once the &lt;code&gt;TestDDA&lt;/code&gt; process is complete. The message looks like this:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientGet&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    URI=CHK@HH-OJMEBuwYC048-Ljph0fh11oOprLFbtB7QDi~4MWw,B~~NJn~XrJIYEOMPLw69Lc5Bv6BcGWoqJbEXrfX~VCo,AAMC--8/pitcairn_justice.jpg&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Identifier=1234&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Verbosity=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ReturnType=disk&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Filename=/tmp/pitcairn_justice.png&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;In this case we&#39;re retreving a file I&#39;ve inserted previously. The &lt;code&gt;Verbosity&lt;/code&gt; key is set to &lt;code&gt;1&lt;/code&gt; to enable &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-SimpleProgress&quot;&gt;SimpleProgress&lt;/a&gt; messages to be received. These messages contain fields showing the total number of blocks that can be fetched for that file, the required number of blocks that we need to get, how many we&#39;ve successfully retrieved so far, and a few other fields. The following bash function processes this and prints the result:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;handle_progress &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;succeeded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;0
      &lt;span class=&quot;nb&quot;&gt;local &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;&amp;quot;&lt;/span&gt;
    
      &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; -r line
      &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^Total&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;total&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##Total=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^Required&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;required&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##Required=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;FinalizedTotal=true&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;final&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;final&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;~ ^Succeeded&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;.* &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nv&quot;&gt;succeeded&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;${line##Succeeded=}&amp;quot;&lt;/span&gt;
       &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;       if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;         &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;echo&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;Progress: retrieved $succeeded out of $required required and $total total ($final)&amp;quot;&lt;/span&gt;
         &lt;span class=&quot;nb&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;       &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;      done&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;code&gt;FinalizedTotal&lt;/code&gt; field indicates if the &lt;code&gt;Total&lt;/code&gt; field is accurate and will not change. Otherwise that field can increase as more knowledge about the file is gained. The &lt;code&gt;Required&lt;/code&gt; field is the number of blocks that need to be received to reconstruct the file. It is less than &lt;code&gt;Total&lt;/code&gt; due to redundancy in the way freenet stores data to account for nodes going away and data being lost.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;handle_progress&lt;/code&gt; function is called from within &lt;code&gt;wait_with_progress&lt;/code&gt;, which waits for a particular message (usually the one indicating the end of the transfer), displays progress, and ignores everything else.&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    &lt;span class=&quot;k&quot;&gt;function &lt;/span&gt;wait_with_progress &lt;span class=&quot;o&quot;&gt;{&lt;/span&gt;
      &lt;span class=&quot;k&quot;&gt;while &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;read&lt;/span&gt; -r line
      &lt;span class=&quot;k&quot;&gt;do&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;        if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;SimpleProgress&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;          &lt;/span&gt;handle_progress
        &lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;        if&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;[&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$line&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;==&lt;/span&gt; &lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt; &lt;span class=&quot;o&quot;&gt;]&lt;/span&gt;; &lt;span class=&quot;k&quot;&gt;then&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;          &lt;/span&gt;&lt;span class=&quot;nb&quot;&gt;break&lt;/span&gt;
&lt;span class=&quot;nb&quot;&gt;        &lt;/span&gt;&lt;span class=&quot;k&quot;&gt;fi&lt;/span&gt;
&lt;span class=&quot;k&quot;&gt;      done&lt;/span&gt;
    &lt;span class=&quot;o&quot;&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;These are called as follows:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientGet&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    URI=CHK@HH-OJMEBuwYC048-Ljph0fh11oOprLFbtB7QDi~4MWw,B~~NJn~XrJIYEOMPLw69Lc5Bv6BcGWoqJbEXrfX~VCo,AAMC--8/pitcairn_justice.jpg&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Identifier=1234&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Verbosity=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ReturnType=disk&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Filename=/tmp/pitcairn_justice.png&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
    
    wait_with_progress &lt;span class=&quot;s2&quot;&gt;&amp;quot;DataFound&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-DataFound&quot;&gt;DataFound&lt;/a&gt; message is sent by the server when the file has been successfully retrieved. It can be found at the location specified in the &lt;code&gt;Filename&lt;/code&gt; field of the &lt;code&gt;ClientGet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/getdisk.sh&quot;&gt;getdisk.sh&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ bash getdisk.sh
Progress: retrieved 0 out of 1 required and 1 total ()
Progress: retrieved 1 out of 1 required and 1 total ()
Progress: retrieved 1 out of 5 required and 10 total ()
Progress: retrieved 1 out of 5 required and 10 total (final)
Progress: retrieved 5 out of 5 required and 10 total (final)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Inserting Data Inline&lt;/h2&gt;

&lt;p&gt;When storing data using FCP you can provide the data directly in the message or reference a file on disk that the node will read and store. They are both done using the &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-ClientPut&quot;&gt;ClientPut&lt;/a&gt; message. Sending this message looks like:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    &lt;span class=&quot;nv&quot;&gt;file&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$1&amp;quot;&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;size&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;stat -c%s &lt;span class=&quot;s2&quot;&gt;&amp;quot;$file&amp;quot;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    &lt;span class=&quot;nv&quot;&gt;mime&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;file --mime-type &lt;span class=&quot;s2&quot;&gt;&amp;quot;$file&amp;quot;&lt;/span&gt; |awk &lt;span class=&quot;s1&quot;&gt;&amp;#39;{print $2}&amp;#39;&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    
    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientPut&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    URI=CHK@&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Metadata.ContentType=$mime&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Identifier=1234&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Verbosity=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    GetCHKOnly=false&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    TargetFilename=$(basename &amp;quot;$file&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    DataLength=$size&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    UploadFrom=direct&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Data&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
    
    dd &lt;span class=&quot;nv&quot;&gt;status&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;none &lt;span class=&quot;k&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$file&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;bs&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;s2&quot;&gt;&amp;quot;$size&amp;quot;&lt;/span&gt; &lt;span class=&quot;nv&quot;&gt;count&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;1 |pv -L 500k &amp;gt;&amp;amp;3
    
    wait_with_progress &lt;span class=&quot;s2&quot;&gt;&amp;quot;PutSuccessful&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    &lt;span class=&quot;nv&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_uri &amp;lt;&amp;amp;3&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;&lt;code&gt;ClientPut&lt;/code&gt; requires the mime type of the file and this is obtained using &lt;code&gt;file&lt;/code&gt;. The size of the file is retrieved with &lt;code&gt;stat&lt;/code&gt;. These are placed in the &lt;code&gt;ClientPut&lt;/code&gt; message directly. The binary data for the file needs to be sent after a &lt;code&gt;Data&lt;/code&gt; terminator similar to how we retrieved the data when doing an inline get. &lt;code&gt;dd&lt;/code&gt; is again used for this but it&#39;s piped to &lt;code&gt;pv&lt;/code&gt; to limit the data transfer rate otherwise the network gets swamped due to buffer bloat.&lt;/p&gt;

&lt;p&gt;The URI for inserting is generated as a CHK key. This is a key based on a hash of the file content. Inserting the same file will result in the same key. &lt;code&gt;get_uri&lt;/code&gt; reads the &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-PutSuccessful&quot;&gt;PutSuccessful&lt;/a&gt; message to find the full key of the insert. This is displayed to the user later in the script.&lt;/p&gt;

&lt;p&gt;The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/putinline.sh&quot;&gt;putinline.sh&lt;/a&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ bash putinline.sh /tmp/example.txt 
Progress: inserted 0 out of 1 ()
Progress: inserted 0 out of 2 ()
Progress: inserted 0 out of 2 (final)
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Inserting Data from Disk&lt;/h2&gt;

&lt;p&gt;Inserting data directly from a disk file works very similar to requesting from a disk file. It requires the &lt;code&gt;TestDDA&lt;/code&gt; process followed by a &lt;code&gt;ClientPut&lt;/code&gt; using a &lt;code&gt;UploadFrom&lt;/code&gt; set to &lt;code&gt;disk&lt;/code&gt;:&lt;/p&gt;

&lt;div class=&quot;highlight&quot;&gt;&lt;pre&gt;&lt;code class=&quot;bash&quot;&gt;    cat &amp;gt;&amp;amp;3 &lt;span class=&quot;s&quot;&gt;&amp;lt;&amp;lt;HERE&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    ClientPut&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    URI=CHK@&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Metadata.ContentType=$mime&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Identifier=1234&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Verbosity=1&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    GetCHKOnly=false&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    TargetFilename=$(basename &amp;quot;$file&amp;quot;)&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    Filename=$file&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    UploadFrom=disk&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    EndMessage&lt;/span&gt;
&lt;span class=&quot;s&quot;&gt;    HERE&lt;/span&gt;
    
    wait_with_progress &lt;span class=&quot;s2&quot;&gt;&amp;quot;PutSuccessful&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
    &lt;span class=&quot;nv&quot;&gt;uri&lt;/span&gt;&lt;span class=&quot;o&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;k&quot;&gt;$(&lt;/span&gt;get_uri &amp;lt;&amp;amp;3&lt;span class=&quot;k&quot;&gt;)&lt;/span&gt;
    wait_for &lt;span class=&quot;s2&quot;&gt;&amp;quot;EndMessage&amp;quot;&lt;/span&gt; &amp;lt;&amp;amp;3
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;


&lt;p&gt;The full bash script is available in &lt;a href=&quot;http://bluishcoder.co.nz/freenet/bash/putdisk.sh&quot;&gt;putdisk.sh&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;Other Messages&lt;/h2&gt;

&lt;p&gt;There are other interesting messages that are useful. Using &lt;code&gt;ClientPut&lt;/code&gt; if you set the field &lt;code&gt;GetCHKOnly&lt;/code&gt; to &lt;code&gt;true&lt;/code&gt; then the file isn&#39;t inserted but the &lt;code&gt;CHK&lt;/code&gt; key is generated. Since &lt;code&gt;CHK&lt;/code&gt; is based on the file contents it will be the same key if the file is inserted using the same mime type, filename and other parameters. This allows generating a key, sending it to a third party and they can start a file retrieval before the file completes inserting. There are security issues with this in that if an attacker knows the key while it is being inserted they may be able to narrow down the location of the inserting node.&lt;/p&gt;

&lt;p&gt;Another useful message is &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-GenerateSSK&quot;&gt;GenerateSSK&lt;/a&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;GenerateSSK
Identifier=1234
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This results in a &lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-SSKKeypair&quot;&gt;SSKKeypair&lt;/a&gt; reply containing a randomly generated &lt;code&gt;SSK&lt;/code&gt; insert and request key:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;SSKKeypair
InsertURI=SSK@AK.../
RequestURI=SSK@Bn.../
Identifier=1234
EndMessage
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These can be used to insert data with &lt;code&gt;ClientPut&lt;/code&gt; by setting the &lt;code&gt;URI&lt;/code&gt; to the &lt;code&gt;InsertURI&lt;/code&gt;, and retrieved by a third party using the &lt;code&gt;RequestURI&lt;/code&gt; as the &lt;code&gt;URI&lt;/code&gt; in &lt;code&gt;ClientGet&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/freenet/wiki/wiki/FCPv2-ClientPutDiskDir&quot;&gt;ClientPutDiskDir&lt;/a&gt; inserts an entire directory. This is the basis of inserting &#39;Freesites&#39; - Freenet websites. I wrote a &lt;a href=&quot;http://bluishcoder.co.nz/freenet/mirror/index.html&quot;&gt;mirror.sh&lt;/a&gt; utility that mirrors an online website or page and inserts it into Freenet. This is useful for linking to news articles in Freenet without having to leave the Freenet environment. It uses a &lt;code&gt;putdir.sh&lt;/code&gt; script that inserts a directory.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;The Freenet API has a lot of functionality beyond what I&#39;ve shown here. I used bash for the examples because it has few dependancies but more robust scripts would be easier in a full featured programming language. I&#39;m not a bash expert and welcome corrections and additions. I&#39;ve put the code in an &lt;a href=&quot;https://github.com/doublec/fcp-examples&quot;&gt;fcp-examples&lt;/a&gt; github repository.&lt;/p&gt;

&lt;p&gt;There are some client libraries with &lt;a href=&quot;https://github.com/freenet/pyFreenet&quot;&gt;pyFreenet&lt;/a&gt; being an example. I recommend the following articles for a deeper dive into Freenet programming:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;http://www.draketo.de/light/english/freenet/communication-primitives-1-files-and-sites&quot;&gt;Freenet Communication Primitives: Part 1, Files and Sites&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://www.draketo.de/light/english/freenet/communication-primitives-2-discovery&quot;&gt;Freenet Communication Primitives: Part 2, Service Discovery and Communication&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Using Freenet over Tor</title>
   <link href="http://bluishcoder.co.nz/2016/08/18/using-freenet-over-tor.html"/>
   <updated>2016-08-18T18:00:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2016/08/18/using-freenet-over-tor</id>
   <content type="html">&lt;p&gt;This post outlines a method of using Freenet over Tor based on posts I wrote on my Freenet hosted blog and subsequent discussions about it. If you read my Freenet hosted blog there&#39;s little new here, I&#39;m just making it available on my non-freenet blog.&lt;/p&gt;

&lt;p&gt;One issue I&#39;ve had with &lt;a href=&quot;https://freenetproject.org/&quot;&gt;Freenet&lt;/a&gt; is that it exposes your IP address to peers. Recent law enforcement efforts to monitor Freenet have shown that they have been able to obtain search warrants based on logging requests for blocks of known data and associating them with IP addresses. If law enforcement can do this, so can random bad people.&lt;/p&gt;

&lt;p&gt;You can avoid exposing your IP address to random strangers on opennet by using darknet but even then you have to trust your friends aren&#39;t monitoring your requests. If it was possible to run Freenet over Tor hidden services then only the hidden service address would be exposed using this logging method. A problem is that Freenet uses UDP which Tor does not support.&lt;/p&gt;

&lt;p&gt;A &lt;a href=&quot;https://emu.freenetproject.org/pipermail/devl/2016-June/039056.html&quot;&gt;recent post on the Freenet development mailing list&lt;/a&gt; pointed out that &lt;a href=&quot;https://www.onioncat.org/&quot;&gt;onioncat&lt;/a&gt; provides a virtual network over Tor and tunnels UDP. Using the steps they provided, and some tweaks, it&#39;s possible to set up a darknet node that doesn&#39;t expose its IP address. It uses the &lt;code&gt;onioncat&lt;/code&gt; generated IPv6 address for communicating with peers - and this address is backed by a Tor hidden service.&lt;/p&gt;

&lt;p&gt;The steps below outline how to set this up. Note that this is quite experimental and requires care to not expose your IP address. There are some Freenet issues that make things difficult so you should be aware that you do this at your risk and understand it may still expose your identity if things go wrong.&lt;/p&gt;

&lt;p&gt;I&#39;m assuming a Debian/Ubuntu like system for the steps.&lt;/p&gt;

&lt;h2&gt;Install Tor&lt;/h2&gt;

&lt;p&gt;Install Tor:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo apt-get install tor
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit the &lt;code&gt;/etc/tor/torrc&lt;/code&gt; file to enable a Hidden Service with an entry like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;HiddenServiceDir /var/lib/tor/freenet/
HiddenServicePort 8060 127.0.0.1:8060
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart Tor and find your hidden service hostname:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo systemctl restart tor
$ sudo cat /var/lib/tor/freenet/hostname
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Install onioncat&lt;/h2&gt;

&lt;p&gt;Install onioncat:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo apt-get install onioncat
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit &lt;code&gt;/etc/default/onioncat&lt;/code&gt; and change the lines matching the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ENABLED=yes
DAEMON_OPTS=&quot;-d 0 hiddenservicename.onion -U&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Restart onioncat:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ sudo systemctl stop onioncat
$ sudo systemctl start onioncat
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Find your onioncat IP address with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ocat -i hiddenservicename.onion
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Install Freenet&lt;/h2&gt;

&lt;p&gt;&lt;a href=&quot;https://freenetproject.org/download.html#download&quot;&gt;Install Freenet in the usual way&lt;/a&gt; and go through the browser based setup wizard. Choose &quot;Details settings: (custom)&quot; for the security option. On the subsequent pages of the wizard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disable the UPnP plugin.&lt;/li&gt;
&lt;li&gt;Choose &quot;Only connect to your friends&quot;&lt;/li&gt;
&lt;li&gt;Choose &quot;High&quot; for &quot;Protection against a stranger attacking you over the internet&quot;&lt;/li&gt;
&lt;li&gt;Click the &quot;I trust at least one person already using Freenet&quot; checkbox.&lt;/li&gt;
&lt;li&gt;For &quot;Protection of your downloads...&quot; pick any option you want.&lt;/li&gt;
&lt;li&gt;Pick a node name that your darknet friends will see.&lt;/li&gt;
&lt;li&gt;Pick a datastore size that you want.&lt;/li&gt;
&lt;li&gt;Choose the bandwidth limit.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The node will now be started but have no connections. There will be warnings about this.&lt;/p&gt;

&lt;h2&gt;Configure Freenet over Tor&lt;/h2&gt;

&lt;p&gt;The following settings need to be changed in &quot;Configuration/Core Settings&quot; - make sure you have clicked &quot;Switch to advanced mode&quot;.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Change &quot;IP address override&quot; to your onioncat IP address retrieved in the previous section.&lt;/li&gt;
&lt;li&gt;Apply the changes.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;Shut down Freenet and edit the &lt;code&gt;wrapper.conf&lt;/code&gt; file in the Freenet installation directory. Change the line that contains &lt;code&gt;java.net.preferIPv4Stack=true&lt;/code&gt; to &lt;code&gt;java.net.preferIPv4Stack=false&lt;/code&gt;. In my &lt;code&gt;wrapper.conf&lt;/code&gt; this is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wrapper.java.additional.3=-Djava.net.preferIPv4Stack=false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit &lt;code&gt;freenet.ini&lt;/code&gt; file in the Freenet installation directory. Change or add the following (replace &quot;onioncat IP address&quot; with the IP address obtained installing &lt;code&gt;onioncat&lt;/code&gt;):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;node.opennet.bindTo=onioncat IP address
node.bindTo=onioncat IP address
node.load.subMaxPingTime=2500
node.load.maxPingTime=5k
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Save the file and restart Freenet. There might be a warning about &quot;Unknown external address&quot;. Ignore this as you&#39;ve explictly set one. I provide a patch later in this post if you want to get rid of the warning.&lt;/p&gt;

&lt;h2&gt;Add a friend&lt;/h2&gt;

&lt;p&gt;Now is the time to add a Darknet friend who is also using Tor/Onioncat. Go to &quot;Friends/Add a friend&quot;. Choose your trust and ability to see other friends settings and enter a description of the friend. Paste their &lt;code&gt;noderef&lt;/code&gt; in the &quot;Enter node reference directly&quot; box.&lt;/p&gt;

&lt;p&gt;Give your noderef to your friend and have them add it. Once both connections have been added you should see &quot;Connected&quot; in the Friends list for that connection. The IP address should show the onioncat IPv6 address, beginning with &quot;fd&quot;.&lt;/p&gt;

&lt;h2&gt;Optional Freenet patch&lt;/h2&gt;

&lt;p&gt;When running a Tor based node Freenet thinks the onioncat IP address is a local address. Some places in the Freenet code base check for this and reject it as a valid global routable address. In the FProxy user interface a large warning appears on each page that it couldn&#39;t find the external IP address of the node. The other issue is that local addresses aren&#39;t counted for bandwidth statistic reporting. The bandwidth box on the statistics page is empty as a result.&lt;/p&gt;

&lt;p&gt;I use a patch, &lt;a href=&quot;http://bluishcoder.co.nz/freenet/onioncat.txt&quot;&gt;onioncat.txt&lt;/a&gt;, that provides a workaround for these two issues. The patch is optional as the node works without it but it&#39;s a useful improvement if you plan to run a Tor based node long term. You should check the patch before applying it blindly and assure that it&#39;s not doing anything nefarious.&lt;/p&gt;

&lt;h2&gt;Hybrid nodes&lt;/h2&gt;

&lt;p&gt;If you run a Tor based darknet node then at least one hybrid node must be in the darknet to bridge to the non-tor nodes. These hybrid nodes will have a public clearnet IP address exposed. I outline how to set up a hybrid node later below. For those that trust me, if you send a darknet tor noderef to me at the freemail address on the bottom of this page, or via normal email, I&#39;ll connect and send you a noderef of a hybrid node setup in this manner.&lt;/p&gt;

&lt;p&gt;Install Tor and Onioncat as described previously. Install Freenet in the usual way and go through the browser based setup wizard. Choose &quot;Details settings: (custom)&quot; for the security option. On the subsequent pages of the wizard:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Enable or Disable the UPnP plugin as necessary depending on what you need for your clearnet connection to work.&lt;/li&gt;
&lt;li&gt;Choose &quot;Connect to strangers&quot;&lt;/li&gt;
&lt;li&gt;Choose &quot;Low&quot; or &quot;Normal&quot; security as desired.&lt;/li&gt;
&lt;li&gt;For &quot;Protection of your downloads...&quot; pick any option you want.&lt;/li&gt;
&lt;li&gt;Pick a datastore size that you want.&lt;/li&gt;
&lt;li&gt;Choose the bandwidth limit.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;The node will start and connect to opennet.&lt;/p&gt;

&lt;p&gt;Shut down Freenet and edit the &lt;code&gt;wrapper.conf&lt;/code&gt; file in the Freenet installation directory. Change the line that contains &lt;code&gt;java.net.preferIPv4Stack=true&lt;/code&gt; to &lt;code&gt;java.net.preferIPv4Stack=false&lt;/code&gt;. In my &lt;code&gt;wrapper.conf&lt;/code&gt; this is:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;wrapper.java.additional.3=-Djava.net.preferIPv4Stack=false
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Edit &lt;code&gt;freenet.ini&lt;/code&gt; file in the Freenet installation directory. Change or add the following:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;node.load.subMaxPingTime=2500
node.load.maxPingTime=5k
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Save the file and restart Freenet. If you base64 decode the &quot;physical.udp&quot; section of the noderef for the node you should see that it now contains the onioncat IP address as well as the public clearnet IP address.&lt;/p&gt;

&lt;p&gt;Adding friends to this node will give those friends access to the wider Freenet datastore when they reciprocate.&lt;/p&gt;

&lt;p&gt;Don&#39;t forget to check your noderefs to ensure that the ARK and the public IP address contain data you are willing to reveal. Check both the &lt;a href=&quot;http://127.0.0.1:8888/friends/myref.txt&quot;&gt;darknet noderef&lt;/a&gt; and the &lt;a href=&quot;http://127.0.0.1:8888/strangers/myref.txt&quot;&gt;opennet noderef&lt;/a&gt;. You can decode the base64 of the &quot;physical.udp&quot; line with the GNU &lt;code&gt;base64&lt;/code&gt; command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ echo &quot;physical.udp base64 here&quot; |base64 -d
&lt;/code&gt;&lt;/pre&gt;

&lt;h2&gt;Final steps and caveats&lt;/h2&gt;

&lt;p&gt;Try visiting a Freenet index site and see if it loads. If it does then the Freenet over Tor setup is working. It will be slower than normal Freenet usage due to Tor latency. If you connect to more darknet nodes it will get faster.&lt;/p&gt;

&lt;p&gt;When adding a friends noderef you can check what IP addresses it will connect to by looking at the &quot;physical.udp&quot; line. This is a base64 encoded list of IP addresses. You might want to check this to ensure that there are no clearnet addresses in there. If there is a clearnet address then it could deanonymize your node when it tries to connect to that in preference to the onioncat address.&lt;/p&gt;

&lt;p&gt;The &quot;ark.pubURI&quot; portion of the noderef is an SSK that points to updated IP address information. A node can subscribe to the USK version of this and learn about IP address changes. Your friends node could change their IP address to a clearnet address resulting in you connecting to that.&lt;/p&gt;

&lt;p&gt;To avoid the above two issues it&#39;s worthwhile running Freenet in a VM or container that does not have clearnet network access and only has access to the onioncat network setup. Alternatively you can use iptables to only allow onioncat traffic for the Freenet process or user running it.&lt;/p&gt;

&lt;p&gt;The IP addresses exposed in the noderef include all local link addresses and their scopes. This is Freenet bug &lt;a href=&quot;https://bugs.freenetproject.org/view.php?id=6879&quot;&gt;6879&lt;/a&gt;. This may leak information you don&#39;t want leaked. It pays to check the &quot;physical.udp&quot; and &quot;ark.pubURI&quot; to see what you are exposing. Remember that any IP addresses exposed over the ARK is discoverable by looking at previous editions of the USK.&lt;/p&gt;

&lt;p&gt;The traffic footprint of Freenet may make it easier to track down your IP address from your Tor ID. The volume of data and the nature of the traffic may make certain types of Tor de-anonymization techniques more effective.&lt;/p&gt;

&lt;p&gt;Ideally it would be possible to have an opennet of Tor nodes so the exchange of darknet noderefs wouldn&#39;t be needed. I haven&#39;t been able to get this working yet but I&#39;ll continue to investigate it.&lt;/p&gt;

&lt;p&gt;I&#39;ve been running a Tor darknet node for the past week to test how well it works. With three darknet connections it runs well enough for browsing freesites. &lt;a href=&quot;http://freesocial.draketo.de/sone_en.html&quot;&gt;Sone&lt;/a&gt; and the &lt;a href=&quot;http://freesocial.draketo.de/wot_en.html&quot;&gt;Web of Trust&lt;/a&gt; took quite a while to bootstrap due to the lower speed but once it was running it works well. &lt;a href=&quot;http://freesocial.draketo.de/fms_en.html&quot;&gt;FMS&lt;/a&gt; and &lt;a href=&quot;http://freesocial.draketo.de/flip_en.html&quot;&gt;Flip&lt;/a&gt; are also usable. I&#39;d expect performance to be even better with more connections.&lt;/p&gt;
</content>
 </entry>
 
 <entry>
   <title>Using Freenet for Static Websites</title>
   <link href="http://bluishcoder.co.nz/2015/09/14/using-freenet-for-static-websites.html"/>
   <updated>2015-09-14T19:00:00+12:00</updated>
   <id>http://bluishcoder.co.nz/2015/09/14/using-freenet-for-static-websites</id>
   <content type="html">&lt;p&gt;This website is generated from markdown to static HTML and I mirror it on &lt;a href=&quot;https://freenetproject.org/&quot;&gt;Freenet&lt;/a&gt;. Data on Freenet slowly disappears if it is not regularly requested and this happens to parts of the mirror of my blog since many posts have a small target audience and the cross section of Freenet users and that target audience results in a low number of requests.&lt;/p&gt;

&lt;p&gt;I&#39;ve thought about changing the clearnet site so it is a thin proxy in front of a Freenet node and retrieves the data from Freenet. This enables all the clearnet requests to contribute to the healing of the Freenet data. It also means an update to the site on Freenet will automatically be reflected in the clearnet version.&lt;/p&gt;

&lt;p&gt;The recent announcement of &lt;a href=&quot;https://ipfs.io/ipfs/QmNhFJjGcMPqpuYfxL62VVB9528NXqDNMFXiqN5bgFYiZ1/its-time-for-the-permanent-web.html&quot;&gt;Neocities mirroring their sites on IPFS&lt;/a&gt; prompted me to try this on Freenet to see how viable it was.&lt;/p&gt;

&lt;p&gt;I&#39;ve been able to get something working and this site is now being served directly from the Freenet data with nginx acting as a caching reverse proxy. Performance is acceptable. Taking this approach has a security tradeoff in that I&#39;ve had to lock down internal node pages that may allow manipulating the node directly. See the end of this post for details on this.&lt;/p&gt;

&lt;p&gt;Freenet has an API called &lt;a href=&quot;https://wiki.freenetproject.org/FCPv2&quot;&gt;FCP&lt;/a&gt; that allows retrieval of content programatically. I thought about writing a simple HTTP proxy server that would retrieve the requests from Freenet via FCP and send them back to the requester. I didn&#39;t want to invest too much effort into a proof of concept so I looked to see if there are existing tools to do this.&lt;/p&gt;

&lt;p&gt;&lt;a href=&quot;https://github.com/saces/SCGIPublisher/&quot;&gt;SCGIPublisher&lt;/a&gt; is a plugin for Freenet that provides an &lt;a href=&quot;https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface&quot;&gt;SCGI&lt;/a&gt; interface to Freenet content using a whitelist to expose only the desired data. It expects to be exposing actual Freenet URIs and keys. I want to hide all this behind my standard domain and I couldn&#39;t work out how to prevent the filtering of data and rewriting of URLs that it does. An example of SCGIPublish usage is &lt;a href=&quot;https://d6.gnutella2.info/freenet/&quot;&gt;d6.gnutella2.info&lt;/a&gt; - it&#39;s a proxy that  provides access to a number of Freenet sites from clearnet.&lt;/p&gt;

&lt;p&gt;Freenet already has a built in proxy, &lt;a href=&quot;https://wiki.freenetproject.org/FProxy&quot;&gt;FProxy&lt;/a&gt;. It does filtering of the requested data to remove JavaScript and detect potentially  malicious file formats. If I could disable this filtering and use &lt;a href=&quot;http://nginx.org&quot;&gt;nginx&lt;/a&gt; as a reverse proxy I&#39;d be able to get what I wanted without writing any code. It turns out this can be disabled by doing the following:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In the Freenet node &lt;code&gt;Configuration/Web Interface&lt;/code&gt; menu, set &quot;Disable progress page when loading pages?&quot; to &lt;code&gt;false&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;p&gt;In the same menu, set &quot;Maximum size of transparent pass-through in the web interface where we cannot show progress&quot; and &quot;Maximum size for transparent pass-through in the web interface where we can show a progress bar&quot; to something higher than the maximum file size of the site you are exposing. Without this the user will receive an HTML page instead of the required content if the content is large.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Append &quot;?forcedownload=true&quot; to all requested URLs.&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;With this setup an nginx reverse proxy can be created that uses the Freenet node web interface as the upstream. Unfortunately setting &lt;code&gt;?forcedownload=true&lt;/code&gt; results in Freenet not sending the mime type for the content so I had to create a lookup table in nginx to compute the mime type. This table looks like:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;map $uri $custom_content_type {
     default         &quot;text/html&quot;;
     ~(.*\.xml)$  &quot;text/xml&quot;;
     ~(.*\.rss)$  &quot;application/rss+xml&quot;;
     ~(.*\.png)$  &quot;image/png&quot;;
     ~(.*\.gif)$  &quot;image/gif&quot;;
     ~(.*\.jpg)$  &quot;image/jpeg&quot;;
     ~(.*\.pdf)$  &quot;application/pdf&quot;;
     ..etc...
 }
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the &lt;code&gt;server&lt;/code&gt; section of the configuration I set up some high timeout values to cater for the inital slowness of the freenet node. I intercept the &lt;code&gt;404&lt;/code&gt; and &lt;code&gt;500&lt;/code&gt; error pages to display some static HTML error messages. This stops the Freenet proxy error pages from having internal links allowing doing things on the node.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
    listen       80;
    server_name proxy.example.com;

    proxy_intercept_errors on;
    error_page 404 /404.html;
    error_page 500 /500.html;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    proxy_read_timeout 300;
    send_timeout 300;
    try_files $uri $uri/index.html;
    location /404.html {
        root /var/www/html/;
        allow all;
        internal;
    }
    location /500.html {
        root /var/www/html/;
        allow all;
        internal;
    }
    ... location blocks ...
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Following that comes the &lt;code&gt;location&lt;/code&gt; blocks. These are hardcoded for the Freenet keys being exposed to prevent the proxy being used to browse any Freenet site. I&#39;ve shortened the actual key below with &lt;code&gt;....&lt;/code&gt; to keep the example short.&lt;/p&gt;

&lt;p&gt;This block hides headers returned by the Freenet proxy, adds the &lt;code&gt;?forcedownload=true&lt;/code&gt; query parameter and sets the &lt;code&gt;proxy_pass&lt;/code&gt; to go to the Freenet node with the hardcoded key.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;location /freenet/USK@..../bluishcoder/ {
        proxy_intercept_errors on;

        index index.html;
        proxy_redirect
            ~^/freenet:USK@..../bluishcoder/(?&amp;lt;edition&amp;gt;[0-9]+)/(.*)\?forcedownload=true$
            /freenet/USK@..../bluishcoder/$edition/$2;
        set $args forcedownload=true;
        proxy_hide_header Content-Type;
        proxy_hide_header Content-Transfer-Encoding;
        proxy_hide_header Content-Disposition;
        proxy_hide_header X-Content-Type-Options;
        proxy_hide_header X-Content-Security-Policy;
        proxy_hide_header X-Webkit-Csp;
        proxy_hide_header Content-Security-Policy;
        proxy_hide_header Cache-Control;
        proxy_hide_header Pragma;
        add_header Content-Type $custom_content_type;
        error_page 301 302 307 =200 @redir;

        proxy_pass http://127.0.0.1:8888/USK@..../bluishcoder/;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;&lt;code&gt;USK&lt;/code&gt; keys have an edition number that is incremented every time a site is updated. I bookmark the &lt;code&gt;USK&lt;/code&gt; key in the node which results in it subscribing for updates and it will automatically pick up the latest edition, even if a request in the nginx configuration file is coded to use a specific edition number.&lt;/p&gt;

&lt;p&gt;I don&#39;t include the &lt;code&gt;USK&lt;/code&gt; edition number in the &lt;code&gt;proxy_pass&lt;/code&gt; request here to make handling edition updates easier. If a request is made for an edition where a later one is available the node will send a &lt;code&gt;301&lt;/code&gt; redirect. The &lt;code&gt;Location&lt;/code&gt; header in the redirect is of the format &lt;code&gt;freenet:USK@.../bluishcoder/edition/...&lt;/code&gt;. The &lt;code&gt;edition&lt;/code&gt; is a numeric value of the latest edition number. The &lt;code&gt;proxy_redirect&lt;/code&gt; statement rewrites this into the URL format that our &lt;code&gt;location&lt;/code&gt; block uses.&lt;/p&gt;

&lt;p&gt;At this point the &lt;code&gt;error_page&lt;/code&gt; statement is hit which converts the &lt;code&gt;301&lt;/code&gt; location moved response to  a &lt;code&gt;200&lt;/code&gt; (HTTP OK response) and passes it to a &lt;code&gt;redir&lt;/code&gt; block:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;location @redir {
  set $args forcedownload=true;
  proxy_hide_header Content-Type;
  proxy_hide_header Content-Transfer-Encoding;
  proxy_hide_header Content-Disposition;
  proxy_hide_header X-Content-Type-Options;
  proxy_hide_header X-Content-Security-Policy;
  proxy_hide_header X-Webkit-Csp;
  proxy_hide_header Content-Security-Policy;
  proxy_hide_header Cache-Control;
  proxy_hide_header Pragma;
  add_header Content-Type $custom_content_type;

  set $foo $upstream_http_location;
  proxy_pass http://127.0.0.1:8888$foo;
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This block saves the original upstream HTTP &lt;code&gt;Location&lt;/code&gt; header (The rewritten one in our own URL format) and passes it back to the proxy to get the data. In this way updated USK editions are handled even though requests are made for earlier editions.&lt;/p&gt;

&lt;p&gt;With this in place we have a Freenet proxy for whitelisted URLs that work with requests lke &lt;code&gt;http://proxy.example.com/freenet/USK@.../bluishcoder/17/...&lt;/code&gt;. Putting another reverse proxy in front of this allows standard clearnet URLs to be used:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;server {
    listen       80;
    server_name example.com;

    proxy_intercept_errors on;
    error_page 404 /404.html;
    error_page 500 /500.html;
    proxy_connect_timeout 300;
    proxy_send_timeout 300;
    proxy_read_timeout 300;
    send_timeout 300;
    try_files $uri $uri/index.html;
    location /404.html {
        root /var/www/html/;
        allow all;
        internal;
    }
    location /500.html {
        root /var/www/html/;
        allow all;
        internal;
    }

    location / {
        index index.html;
        proxy_pass http://proxy.example.com/freenet/USK@..../bluishcoder/17/;
    }
}
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now requests to &lt;code&gt;http://example.com&lt;/code&gt; proxy to the Freenet &lt;code&gt;USK&lt;/code&gt; and avoids the internal filtering and progress pages.&lt;/p&gt;

&lt;p&gt;I&#39;ve got this site running with this setup and it works pretty well. I use nginx proxy caching to cache requests for a period of time to ease the load on the Freenet node. There are some rough edges. The first request for a large file, video for example, takes a while as it has to download the entire video - it can&#39;t stream it. Once it is cached by nginx then streaming to other requests is fine.&lt;/p&gt;

&lt;p&gt;Taking this approach got things working quickly but I think in the long term it would be better to take the approach of writing a proxy that utilizes FCP as described earlier. This would enable using the mime type that Freenet knows for the files, avoiding the manual table in the nginx configuration, and avoids any possible security issues from accidentally leaking internal Freenet proxy pages. It helps prove the approach as viable however.&lt;/p&gt;

&lt;h2&gt;Security Tradeoffs&lt;/h2&gt;

&lt;p&gt;If an internal node page somehow became available to the user they may be able to access any Freenet URL, download files to any location on the machine and upload any files on the machine. They can reconfigure the node and create connections to other nodes.&lt;/p&gt;

&lt;p&gt;To restrict the damage they can do I&#39;ve changed the following settings on the node:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;In &lt;code&gt;Configuration/Core Settings&lt;/code&gt; change the &quot;Directories downloading is allowed to&quot; to empty. This prevents the node being used to download files to disk.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Configuration/Core Settings&lt;/code&gt; change the &quot;Directories uploading is allowed from&quot; to empty. This prevents the node being used to upload files.&lt;/li&gt;
&lt;li&gt;In &lt;code&gt;Configuraiton/Web Interface&lt;/code&gt; change &quot;Public Gateway Mode&quot; to true. This will prevent the user from being able to change any node settings. You should configure an IP address for an admin user to access the node with full administation settings. Optionally, and what I do, is enable it for all users. If I want to temporarily administer the node I shut it down from a shell, edit &lt;code&gt;freenet.ini&lt;/code&gt; to change &lt;code&gt;fproxy.publicGatewayMode&lt;/code&gt; to &lt;code&gt;false&lt;/code&gt;, and restart.&lt;/li&gt;
&lt;/ul&gt;


&lt;p&gt;These issues would go away if a proxy that uses FCP, or a Freenet plugin that does similar, was created.&lt;/p&gt;

&lt;h2&gt;Related Links&lt;/h2&gt;

&lt;p&gt;Some links that provide related information on Freenet are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href=&quot;https://d6.gnutella2.info/freenet/&quot;&gt;d6.gnutella2.info&lt;/a&gt; - Provides clearnet access to some Freenet sites.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://draketo.de/light/english/freenet/communication-primitives-1-files-and-sites&quot;&gt;Freenet Communication Primitives: Part 1, Files and Sites&lt;/a&gt; - Useful information for programming with FCP.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;http://draketo.de/light/english/freenet/communication-primitives-2-discovery&quot;&gt;Freenet Communication Primitives: Part 2, Service Discovery and Communication&lt;/a&gt; - More information on programming with FCP.&lt;/li&gt;
&lt;li&gt;&lt;a href=&quot;https://d6.gnutella2.info/freenet/USK@sUm3oJISSEU4pl2Is9qa1eRoCLyz6r2LPkEqlXc3~oc,yBEbf-IJrcB8Pe~gAd53DEEHgbugUkFSHtzzLqnYlbs,AQACAAE/random_babcom/131/#MirroringalinkintoFreenet&quot;&gt;Mirroring a link into Freenet&lt;/a&gt; - Describes how to get a site onto Freenet using freesitemgr and &lt;a href=&quot;https://github.com/ArneBab/lib-pyFreenet-staging/tree/copyweb&quot;&gt;pyFreenet&lt;/a&gt;.&lt;/li&gt;
&lt;/ul&gt;

</content>
 </entry>
 
 <entry>
   <title>Using Freenet</title>
   <link href="http://bluishcoder.co.nz/2014/12/18/using-freenet.html"/>
   <updated>2014-12-18T17:00:00+13:00</updated>
   <id>http://bluishcoder.co.nz/2014/12/18/using-freenet</id>
   <content type="html">&lt;p&gt;I&#39;ve been following the &lt;a href=&quot;https://freenetproject.org/&quot;&gt;Freenet project&lt;/a&gt; for many years, occasionally firing it up and seeing if I can do anything useful with it. I&#39;ve been using it regularly over the last month and it has come a long way since I first tried it. It&#39;s much faster than what it was in the past. This post describes a bit of how I use it and some of the issues I worked around when publishing content.&lt;/p&gt;

&lt;h2&gt;Overview&lt;/h2&gt;

&lt;p&gt;There are no dynamic servers on Freenet. No user hosts a site. It&#39;s a data store and users push the data into the content store which then becomes retrievable by anyone with the key. Freenet is essentially a large encrypted distributed hash table.&lt;/p&gt;

&lt;p&gt;Nodes set aside an amount of disk space and users choose to store data under a key. Retrieval of the key goes out into the distributed hash table and returns the data associated with it. Inserting data into the store pushes that data out into other nodes and is not generally stored in your own node. Requesting data sends the request over the network and the data migrates to your node to return the data. A scheme is used to enable recovery from data loss. M of N segments of your data can be lost but the full data can still be recovered. The network is lossy in that as more data is inserted, less frequently requested data drops out. Data stored is immutable. Once it is in the store with a key it will always be associated with that data.&lt;/p&gt;

&lt;p&gt;Freenet data is requested using keys. There are different types of keys. A high level overview would be:&lt;/p&gt;

&lt;dl&gt;
  &lt;dt&gt;KSK@somewhere&lt;/dt&gt;
  &lt;dd&gt;A KSK key can be chosen by the inserter. The &#39;somewhere&#39; portion of the key can be any value. This allows generating keys to access data using easier to remember words or phrases. The downside is they can be re-inserted by anyone with different data. What you get when you request the key depends on what data has been inserted by different users under it.&lt;/dd&gt;
  &lt;dt&gt;CHK@...&lt;/dt&gt;
  &lt;dd&gt;CHK keys have the `...` portion computed based on the hash of the data content. These have the advantage that the key is always the same for the same data. If data for a CHK key has dropped out of the network anyone can &#39;heal&#39; that data by reinserting the same file. The hash for the CHK key will be the same and the data will become available again under that same key. This is like being able to have any user fix a 404 response on the standard internet by reuploading the same file anywhere.&lt;/dd&gt;
  &lt;dt&gt;SSK@...&lt;/dt&gt;
  &lt;dd&gt;An SSK key has a unique cryptographically generated hash that is different for any given insert of data. These cannot be &#39;healed&#39; if the data drops out as a re-insert will have a different key.&lt;/dd&gt;
  &lt;dt&gt;USK@.../foo/1&lt;/dt&gt;
  &lt;dd&gt;A USK key allows updateable content. Note the number at the end. This increments everytime new data for the key is inserted. When requesting data freenet can look for the highest number available and return that. It&#39;s useful for freenet hosted blogs which have reguarly updated content.&lt;/dd&gt;
&lt;/dl&gt;


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

&lt;p&gt;The freenet software really needs to run 24x7 to be effective. I followed the &lt;a href=&quot;https://freenetproject.org/download.html#unix&quot;&gt;headless install instructions&lt;/a&gt; to install on a server machine and access the freenet proxy on my client machines using an SSH tunnel. An SSH commmand like the following sets up local ports that tunnel to the server so they can be accessed locally:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;ssh -L 8888:127.0.0.1:8888 -L 8080:127.0.0.1:8080 -L 9481:127.0.0.1:9481 me@myserver.local
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The &lt;code&gt;8888&lt;/code&gt; port is for the freenet proxy software where you access most freenet functionality from the browser. Port &lt;code&gt;8080&lt;/code&gt; is for the &lt;a href=&quot;http://freesocial.draketo.de/fms_en.html&quot;&gt;Freenet Message System&lt;/a&gt; if you install that and &lt;code&gt;9481&lt;/code&gt; is for the API interface that &lt;a href=&quot;https://freenetproject.org/jsite.html&quot;&gt;jSite&lt;/a&gt; uses.&lt;/p&gt;

&lt;p&gt;It takes a few hours for a new freenet node to establish itself and get up to speed. Expect much slowness initially. It gets better though.&lt;/p&gt;

&lt;h2&gt;Social Networking on Freenet&lt;/h2&gt;

&lt;p&gt;Freenet has some social networking functionality. There is a web of trust for identities, distributed anonymous email, twitter-like microblogging, forums and IRC like chat. How to set these up is described in the &lt;a href=&quot;http://freesocial.draketo.de/&quot;&gt;Freenet Social Networking Guide&lt;/a&gt;. Setting up an identity in the web of trust and Sone for the microblogging will give a good start to using freenet socially.&lt;/p&gt;

&lt;p&gt;You can create as many web of trust identities as you want and switch between them for different purposes. I use Freenet non-anonmously and my identity on there is associated with my real world identity but I could also have anonymous ones for other purposes.&lt;/p&gt;

&lt;h2&gt;Freenet Sites&lt;/h2&gt;

&lt;p&gt;A freenet site is usually stored under a &lt;code&gt;USK&lt;/code&gt; key so it can be updated. Software to insert a directory of HTML as a USK is the easiest way of uploading a site or blog. I use &lt;a href=&quot;https://freenetproject.org/jsite.html&quot;&gt;jSite&lt;/a&gt;. I mirror this blog to freenet under the key &lt;small&gt;USK@1ORdIvjL2H1bZblJcP8hu2LjjKtVB-rVzp8mLty~5N4,8hL85otZBbq0geDsSKkBK4sKESL2SrNVecFZz9NxGVQ,AQACAAE/bluishcoder/-7&lt;/small&gt;. Note the negative number at the end. When requested this results in freenet starting from edition &#39;7&#39; and looking for the most recent published edition from there. Sites can be bookmarked in the freenet proxy and it will automatically look for and update the bookmark when a new edition is inserted.&lt;/p&gt;

&lt;p&gt;There were some issues I had to workaround when mirroring my Jekyll based blog. I have absolute links in the blog that references other pages. These don&#39;t work if copied directly to a freenet site as the freenet proxy has the content key as the initial part of the URL. So a link to a page in the proxy looks like &lt;small&gt;/USK@longhash/bluishcoder/7/2014/12/17/changing-attributes-in-self-objects.html&lt;/small&gt;. An internal link that starts with &lt;code&gt;/&lt;/code&gt; to go to a page will not work as it doesn&#39;t contain the &lt;code&gt;USK&lt;/code&gt; key prefix. I tried modifying Jekyll to use relative URLs but wasn&#39;t successful. The approach I ended up taking was to follow the advice in &lt;a href=&quot;https://github.com/jekyll/jekyll/issues/332#issuecomment-18952908&quot;&gt;this github issue&lt;/a&gt;. My &lt;code&gt;_config.yml&lt;/code&gt; file  contains these &lt;code&gt;baseurl&lt;/code&gt; entries:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;baseurl: &quot;file:///some/path/bluishcoder/_site&quot;
#baseurl: /USK@longlonghash/bluishcoder/7
#baseurl: &quot;http://bluishcoder.co.nz&quot;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;All my internal links in blog posts have the &lt;code&gt;baseurl&lt;/code&gt; prefixed. For example (Remove the backslash - I had to add it to prevent Jekyll from replacing it with the baseurl here):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[link to a video]({\{site.baseurl}}/self/self_comment.webm)
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;This gets replaced at blog generation time by the &lt;code&gt;baseurl&lt;/code&gt; entry in &lt;code&gt;_config.yml&lt;/code&gt;. I generate my internet based blog with the relevant &lt;code&gt;baseurl&lt;/code&gt;, copy that to my webserver, then generate the freenet based one with the correct &lt;code&gt;baseurl&lt;/code&gt; and push that to freenet using jSite. This is a bit tedious but works well. A blog system that uses only relative URLs would be a lot easier as you can just insert the site directly.&lt;/p&gt;

&lt;p&gt;Note that freenet sites cannot use JavaScript and some content is filtered out for security reasons. Simple HTML and CSS works best.&lt;/p&gt;

&lt;h2&gt;Photo heavy sites&lt;/h2&gt;

&lt;p&gt;I have a site heavy in photos which is a mirror of some &lt;a href=&quot;http://cd.pn/pn2012/&quot;&gt;photos from my Pitcairn Island trip&lt;/a&gt;. This is under key &lt;small&gt;USK@2LK9z-pdZ9kWQfw~GfF-CXKC7yWQxeKvNf9kAXOumU4,1eA8o~L~-mIo9Hk7ZK9B53UKY5Vuki6p4I4lqMQPxyw,AQACAAE/pitcairnisland/3&lt;/small&gt;. The interesting problem with photo heavy sites is how best to present the photos while also preventing them from dropping out of the network.&lt;/p&gt;

&lt;p&gt;If the main page of the site has thumbnail images and allows the user to see the full image by selecting the thumbnail then the thumbnails tend to stay alive as they are most requested. Unfortunately some of the full images will tend to drop out eventually. A recommended approach by long time freenet users is to link to the full photo in the IMG tag but scale it to thumbnail size. This causes the page to have all the full size images scaled and is slow to load. But all the images stay alive.&lt;/p&gt;

&lt;p&gt;I like the fast loading approach of thumbnails though so tried to find a middle ground. &lt;a href=&quot;http://www.thecssninja.com/css/even-better-image-preloading-with-css2&quot;&gt;Image preloading using CSS&lt;/a&gt; seemed like a viable solution but Freenet&#39;s content filter has issues with it. With some tweaking of that this approach would work well. The thumbnails would load for quick viewing and the full images would pre-load without the user noticing that the page is still loading. This should result in most images staying around.&lt;/p&gt;

&lt;p&gt;The approach I ended up using was to have a hidden DIV at the end of the page with the full sized images. They don&#39;t display and cause the full size images to be retrieved while the user sits on the main page. The downside is the page still shows that it&#39;s loading which isn&#39;t optimal. I also link to a page that has the full sized images scaled to thumbnail size as a viewing option. Hopefully the issue with the CSS preloading approach can be resolved as that has a better user experience.&lt;/p&gt;

&lt;h2&gt;Conclusion&lt;/h2&gt;

&lt;p&gt;Other than mirring my blog and using Sone I haven&#39;t done too much else. There is a &#39;bitcoin over freenet&#39; program that mirrors the blockchain in freenet and allows submitting and retrieving transactions that looks interesting to explore. Freenet would seem to be useful for some things Tor is used for (dissemination of information under oppressive regimes) without the requirement of needing an active server that can be located and attacked.&lt;/p&gt;

&lt;p&gt;There&#39;s a &lt;a href=&quot;https://www.noname-ev.de/wiki/uploads/9/9b/FreenetSlides.pdf&quot;&gt;great set of PDF slides&lt;/a&gt; that cover more about what Freenet can do if you&#39;re interested in looking into it more.&lt;/p&gt;

&lt;p&gt;My interest has been more about looking at how freenet can be used as a more encrypted and non-hosted distributed alternative to services like Twitter, Facebook, hosted email and the like. As long as you can put up with higher latency and the different idioms an &#39;immutable internet that decays&#39; requires it seems that this is viable.&lt;/p&gt;

&lt;p&gt;I&#39;m curious what other services people could build on top of it.&lt;/p&gt;
</content>
 </entry>
 
 
</feed>
