Transparent I2P tunneling
These notes are to setup an I2P FreeNAS jail to transparently tunnel .i2p traffic using a Ubiquiti EdgeRouter ER-X
Huge kudos to these notes that got me moving in the right direction:
This is the logical flow of what we are going to setup. Pictures really help the understanding.
EdgeRouter ER-X setup
As I have an EdgeRouter ER-X the instructions will cover what you need to configure on this device in terms of the router setup
Setup DNSMASQ on server to catch .i2p DNS requests return the IP 10.191.0.1 as the domain lookup
/etc/dnsmasq.conf address=/i2p/10.191.0.1
Test it out. Any domain ending in .i2p will return the IP 10.191.0.1
# dig @127.0.0.1 hello.i2p ; <<>> DiG 9.9.4-RedHat-9.9.4-51.el7 <<>> @127.0.0.1 hello.i2p ; (1 server found) ;; global options: +cmd ;; Got answer: ;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 8423 ;; flags: qr aa rd ra ad; QUERY: 1, ANSWER: 1, AUTHORITY: 0, ADDITIONAL: 0 ;; QUESTION SECTION: ;hello.i2p. IN A ;; ANSWER SECTION: hello.i2p. 0 IN A 10.191.0.1 ;; Query time: 0 msec ;; SERVER: 127.0.0.1#53(127.0.0.1) ;; WHEN: Tue Dec 19 02:13:21 UTC 2017 ;; MSG SIZE rcvd: 43
We need to configure a NAT rule to redirect our 10.191.0.1:80 traffic to the server running the privoxy/i2p software.
ubnt@ubnt# show service nat nat { rule 1 { description i2p destination { address 10.191.0.1 port 80 } inbound-interface switch0 inside-address { address 192.168.1.14 port 8118 } log disable protocol tcp source { group { address-group !I2P_EXCLUDE } } type destination } rule 5001 { description "masquerade for WAN" outbound-interface eth0 type masquerade } rule 5002 { description "hairpin for i2p" destination { address 192.168.1.0/24 port 8118 } log disable outbound-interface switch0 protocol tcp source { address 192.168.1.0/24 } type masquerade } } ubnt@ubnt# show firewall group address-group I2P_EXCLUDE { address 192.168.1.14 description "exclude these IP address from being routed via i2p proxy" }
We will end up with a NAT configuration like this:
With the following firewall rule.
FreeNAS I2P jail
I run i2p and privoxy inside a FreeNAS jail so these instructions reflect this.
Follow the instructions to setup the I2P jail
Privoxy configuration
Now the I2P jail is setup we need install the privoxy for transparent routing. The jail does not install privoxy.
Install privoxy into the jail and forward .i2p domain name requests to the router.
# pkg install privoxy
Allow it to autostart edit /etc/rc.conf
privoxy_enable="YES"
We need to pre-create this
# mkdir /var/run/privoxy # chown privoxy:privoxy /var/run/privoxy
Start Privoxy manually to create the necessary config files run:
# /usr/local/etc/rc.d/privoxy forcestart
This will create the file /usr/local/etc/privoxy/config
That is hokey. You have to run it to create the config file so you can edit it ?
Edit the configuration file
listen-address 192.168.1.14:8118 accept-intercepted-requests 1 forward .i2p 127.0.0.1:4444
Restart after making those changes
/usr/local/etc/rc.d/privoxy restart
Setting up Opengrok in a FreeNAS 11.2 iocage jail
Create storage dataset's for GROK
Create a jail for GROK
Setup jail mount points for src and data. You need to stop the jail to add mount points and then restart afterwards.
- /mnt/u03/opengrok/src → /var/opengrok/src
- /mnt/u03/opengrok/data → /var/opengrok/data
Find the JAIL and open a shell
root@ale[~]# jls JID IP Address Hostname Path 1 plex /mnt/u02/iocage/jails/plex/root 2 bind /mnt/u02/iocage/jails/bind/root 5 beer /mnt/u02/iocage/jails/beer/root 6 grok /mnt/u02/iocage/jails/grok/root root@ale[~]# jexec 6 /bin/sh
Install opengrok and git. To generate the history caches from GIT based repositories we need the git command line tool.
# pkg install -y opengrok git # pkg info opengrok opengrok-1.0 Name : opengrok Version : 1.0 Installed on : Tue May 14 09:04:03 2019 EDT Origin : devel/opengrok Architecture : FreeBSD:11:* Prefix : /usr/local Categories : devel java Licenses : APACHE20, CDDL Maintainer : ports@FreeBSD.org WWW : http://opengrok.github.io/OpenGrok/ Comment : Fast and powerful code search and cross-reference engine Options : DOCS : on RESIN3 : off TOMCAT6 : off TOMCAT7 : off TOMCAT8 : on TOMCAT85 : off Annotations : repo_type : binary repository : FreeBSD Flat size : 20.5MiB Description : OpenGrok is a fast source code search and cross reference engine. It helps you search, cross-reference and navigate your source tree. It can understand various program file formats and version control histories like Mercurial, Git, SCCS, RCS, CVS, Subversion, Teamware, ClearCase, Perforce and Bazaar. In other words it lets you grok (profoundly understand) the open source, hence the name OpenGrok. It is written in Java. WWW: http://opengrok.github.io/OpenGrok/
This installs tomcat8 we need to autostart this.
# ls /usr/local/etc/rc.d tomcat8
Enable for auto start /etc/rc.conf
echo tomcat8_enable="YES" >>/etc/rc.conf
and start it
service tomcat8 start
This should fire up with an error. That's OK as we have not indexed anything the error will disappear after indexing.
Make a directory
mkdir /var/opengrok/etc
Create a helper script and run it.
cat <<EOF >~/opengrok-index opengrok -c /usr/local/bin/exctags -s /var/opengrok/src -d /var/opengrok/data -H -P -S -G -W /var/opengrok/etc/configuration.xml service tomcat8 restart EOF chmod a+x ~/opengrok-index ~/opengrok-index
The -U parameter only takes host:port and it assumes the WEBAPP is called /source which means the indexer can't tell the running opengrok to reload. So restart tomcat as part of the index run. A minor wart.
Making opengrok the default webapp and use port 80
Moving tomcat from port 8080 to port 80 Edit /usr/local/apache-tomcat-8.0/conf/server.xml file and replace 8080 with 80
<Connector port="80" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" />
Make opengrok the default web application by adding a <Context> tag inside <Host>
<Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"> <Context path="" docBase="/usr/local/apache-tomcat-8.0/webapps/opengrok"> <WatchedResource>WEB-INF/web.xml</WatchedResource> </Context>
Setting up MoinMoin in a FreeNAS 11.2 iocage jail
Create a jail and attach the storage into the JAIL at this location: /usr/local/www/wiki/data
Login to the jail and install moin this version will do nicely.
# pkg search moin moinmoin-1.9.10 Easy to use, full-featured and extensible wiki software package
Install MoinMoin and run the recommend steps installing from a package.
# pkg install -y moinmoin
Setup for WSGI
export MOINSCRIPT="moin.wsgi" export MOINDIR="/usr/local/share/moin" export MOINDEST="/usr/local/www/wiki" export CGIUSER="www" export CGIGROUP="www" mkdir -p ${MOINDEST}/data mkdir -p ${MOINDEST}/underlay cp -R ${MOINDIR}/data ${MOINDEST} cp -R ${MOINDIR}/underlay ${MOINDEST} chmod -R u+rw,go-ws ${MOINDEST}/data install -m 0555 ${MOINDIR}/config/wikiconfig.py ${MOINDEST} test -z "${MOINSCRIPT}" || \ install -m 0555 ${MOINDIR}/server/${MOINSCRIPT} ${MOINDEST} chown -R ${CGIUSER}:${CGIGROUP} ${MOINDEST}
NGINX setup
Based very closely around * https://wiki.freebsd.org/Ports/www/moinmoin
Install nginx and uwsgi server
pkg install -y nginx uwsgi
Replace /usr/local/etc/nginx/nginx.conf with
worker_processes 1; events { worker_connections 1024; } http { include mime.types; default_type application/octet-stream; sendfile on; keepalive_timeout 65; server { listen 80; server_name wiki.local; location / { uwsgi_pass unix:/var/run/moin.sock; include uwsgi_params; } location ~ ^/moin_static[0-9]+/(.*) { alias /usr/local/lib/python2.7/site-packages/MoinMoin/web/static/htdocs/$1; } } }
NOTE: Its important to access the server by a DNS name in the nginx.conf file that resolves to the jail IP. Not doing this will result in the NGINX server not being able to correctly lookup the static content.
Append to /etc/rc.conf
uwsgi_enable="YES" uwsgi_configfile="/usr/local/www/wiki/uwsgi.ini" uwsgi_uid="www" uwsgi_gid="www" nginx_enable="YES"
Create /usr/local/www/wiki/uwsgi.ini
[uwsgi] socket = /var/run/moin.sock chmod-socket = 660 chdir = /usr/local/www/wiki wsgi-file = moin.wsgi master workers = 3 max-requests = 200 harakiri = 30 die-on-term
Wiki config
Allow anybody to edit anything and for them to create their own account.
Add the acl_rights_default entries and uncomment page_front_page and actions_superuser.
/usr/local/www/wiki/wikiconfig.py
class Config(multiconfig.DefaultConfig): # Critical setup --------------------------------------------------- # Directory containing THIS wikiconfig: wikiconfig_dir = os.path.abspath(os.path.dirname(__file__)) acl_rights_default = u"All:read,write,delete,revert,admin" page_front_page = u'FrontPage' actions_superuser = multiconfig.DefaultConfig.actions_superuser[:] actions_superuser.remove('newaccount')
Start it up
service uwsgi start service ngnix start
Xapian
Speeding up searching by enabling xapian
pkg install xapian-core py27-xapian
/usr/local/www/wiki/wikiconfig.py
xapian_search = True xapian_stemming = True
Restart
service uwsgi restart
You can check to see if its enabled by navigating to SystemInfo
Installing the umlsequence diagram plugin
Grab the plugin: https://moinmo.in/ParserMarket/UmlSequence and install the file umlsequence.py into /usr/local/www/wiki/data/plugin/parser/
File with all modification presented below: umlsequence.zip
Install additional packages into the jail:
- plotutils → supplies pic2plot
- ImageMagick7-nox11 → supplied convert
pkg update -f pkg install plotutils pkg install ImageMagick7-nox11
We need to edit the umlsequence.py source code to adjust where the required utilities are installed.
pic2plot path change
# Launch pic2plot => postscript os.system ('/usr/local/bin/pic2plot -T ps "%s" > "%s" 2>"%s"' % (pic, ps, err))
The convert program would not run with just the path to the program. The path /usr/local/bin has to be in the PATH env var.
# Run the postprocessing/conversion chain cmd = 'PATH=$PATH:/usr/local/bin convert -density %dx%d "%s" "%s"' % (opt_percent, opt_percent, ps, pngpath) os.system(cmd)
Enabling the alternative format specification
The src code was modified to include the alt= switch so that original and alternative could be supported in the wiki.
*************** *** 804,813 **** --- 804,815 ---- opt_dbg = False opt_help = None opt_percent = 100 + opt_alt = False for (key, val) in self.attrs.items (): val = val [1:-1] if key == 'debug': opt_dbg = int (val) elif key == 'help': opt_help = val + elif key == 'alt': opt_alt = True elif key == 'percent': opt_percent = int (val) else: self.request.write (formatter.rawHTML (""" *************** *** 845,851 **** lines = raw.split ('\n') # alternate syntax support ! lines = self._convert_from_alternate_1 (lines) # debug ? post-print if opt_dbg==2: --- 847,854 ---- lines = raw.split ('\n') # alternate syntax support ! if opt_alt: ! lines = self._convert_from_alternate_1 (lines) # debug ? post-print if opt_dbg==2:
Using the alternate format to draw diagrams
{{{#!umlsequence alt=1 S : s:Switch P : p:Pump S -> P run() S -> P stop() }}}
The original syntax
{{{#!umlsequence # Object definition object(S,"s:Switch"); object(P,"p:Pump"); # Message exchange message(S,P,"run()"); message(S,P,"stop()"); # Object lifeline completion complete(S); complete(P); }}}
CCB request completed with an error
FreeNAS server was randomly crashing:
(da0:umass-sim0:0:0:0): Retrying command (da0:umass-sim0:0:0:0): WRITE(10). CDB: 2a 00 00 24 26 9d 00 00 10 00 (da0:umass-sim0:0:0:0): CAM status: CCB request completed with an error (da0:umass-sim0:0:0:0): Error 5, Retries exhausted root@freenas:/mnt/data #
The USB drive is causing this.
root@wine:~ # usbconfig ugen0.1: <Intel EHCI root HUB> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen1.1: <Intel EHCI root HUB> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen1.2: <vendor 0x8087 product 0x0024> at usbus1, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen0.2: <vendor 0x8087 product 0x0024> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=SAVE (0mA) ugen0.3: <SanDisk Cruzer Blade> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (224mA) root@wine:~ # usbconfig -u 0 -a 3 dump_device_desc ugen0.3: <SanDisk Cruzer Blade> at usbus0, cfg=0 md=HOST spd=HIGH (480Mbps) pwr=ON (224mA) bLength = 0x0012 bDescriptorType = 0x0001 bcdUSB = 0x0210 bDeviceClass = 0x0000 <Probed by interface class> bDeviceSubClass = 0x0000 bDeviceProtocol = 0x0000 bMaxPacketSize0 = 0x0040 idVendor = 0x0781 idProduct = 0x5567 bcdDevice = 0x0100 iManufacturer = 0x0001 <SanDisk> iProduct = 0x0002 <Cruzer Blade> iSerialNumber = 0x0003 <4C531001561109121142> bNumConfigurations = 0x0001
Switched to a different USB stick and the problem went away.
Lesson: Not all USB sticks are created equally.