IODINE(8)

πŸ’… IODINE(8) β€” like, the iodined manual, bestie ✨

okay so real talk, this is the manual page for iodined β€” that's the server half of the iodine situation, from the System Manager's Manual. Sit down, grab a strawberry something πŸ“, and let me tell you everything.

✨ NAME ✨

iodined β€” tunnel IPv4 over DNS πŸ›°οΈ

🌸 SYNOPSIS 🌸

iodined [-v]

iodined [-h]

iodined [-4] [-6] [-c] [-s] [-f] [-D] [-u user ] [-t chrootdir ] [-d
device ] [-m mtu ] [-l listen_ip4 ] [-L listen_ip6 ] [-p port ] [-n (
auto | external_ip ) ] [-b dnsport ] [-P password ] [-z context ] [-F
pidfile ] [-i max_idle_time ] tunnel_ip [ /netmask ] topdomain

πŸ¦‹ DESCRIPTION πŸ¦‹

iodine lets you tunnel IPv4 data through a DNS server. no cap. this is genuinely useful when your Internet access is firewalled but DNS queries are, like, allowed to sneak through πŸ‘€. it needs a TUN/TAP device to actually operate.

the bandwidth is asymmetrical β€” measured max was 680 kbit/s upstream and 2.3 Mbit/s downstream in a wired LAN test network. and on a Wifi network using a carrier-grade DNS cache, realistic sustained throughput was measured at some 50 kbit/s upstream and over 200 kbit/s downstream. it's giving "slow but it works" energy and honestly? we stan πŸ’…

so iodine is the client application, and iodined β€” the one we're talking about β€” is the server.

Note: server and client are required to speak the exact same protocol. in most cases that means running the same iodine version. unfortunately, implementing backward and forward protocol compatibility is usually not feasible 😭 like, it's just not happening.

πŸ‘‘ OPTIONS πŸ‘‘

  • -v β€” print version info and exit. that's it, that's the whole job ✨
  • -h β€” print usage info and exit. your little help menu moment 🫢
  • -f β€” keep running in foreground. no sneaky background vanishing πŸ’€
  • -4 β€” force/allow only IPv4 DNS queries
  • -6 β€” force/allow only IPv6 DNS queries
  • -u user β€” drop privileges and run as user 'user' after setting up the tunnel. self-care and security bestie πŸ”
  • -t chrootdir β€” chroot to 'chrootdir' after setting up the tunnel.
  • -d device β€” use the TUN device 'device' instead of the normal one, which is dnsX on Linux and otherwise tunX. on macOS 10.6 or newer, this can also be utunX, which will attempt to use an utun device built into the OS. iconic OS-specific behavior 🌈
  • -P password β€” use 'password' to authenticate. if not used, stdin will be used as input. only the first 32 characters will be used. the way that 32 is a hard limit… πŸ‘€
  • -z context β€” apply SELinux 'context' after initialization.
  • -F pidfile β€” create 'pidfile' and write the process id in it.
  • -c β€” disable checking the client IP address on all incoming requests. by default, requests originating from non-matching IP addresses will be rejected β€” but that causes problems when requests are routed via a cluster of DNS servers. so this one's for the cluster girlies πŸ’€
  • -s β€” don't try to configure IP address or MTU. this should only be used if you have already configured the device that will be used. like, please actually have done it πŸ™ˆ
  • -D β€” increase debug level. level 1 prints info about each RX/TX packet, and it implies the -f option. on level 2 (-DD) or higher, DNS queries will be printed literally. when using Base128 upstream encoding, this is best viewed as ISO Latin-1 text instead of (illegal) UTF-8. this is easily done with:
"LC_ALL=C luit iodined -DD ..."

(see luit(1)). lowkey love a niche debugging tip πŸŽ€

  • -m mtu β€” set 'mtu' as mtu size for the tun device. this will be sent to the client on login, and the client will use the same mtu for its tun device. default 1130. note that the DNS traffic will be automatically fragmented when needed. handy πŸ’–
  • -l external|listen_ip4 β€” make the server listen only on 'listen_ip4' for incoming IPv4 requests. by default, incoming requests are accepted from all interfaces (0.0.0.0). a domain name can be used as argument β€” use one with only one A record. if listen_ip4 is external, iodined will use the opendns.com DNS service to retrieve the external IP of the host and use that as listen address. main character networking energy πŸ‘‘
  • -L listen_ip6 β€” make the server listen only on 'listen_ip6' for incoming IPv6 requests. by default, incoming requests are accepted from all interfaces (::). a domain name can be used as argument β€” use one with only one AAAA record.
  • -p port β€” make the server listen on 'port' instead of 53 for traffic. if 'listen_ip4' does not include localhost, this 'port' can be the same as 'dnsport'.
Note: you must make sure the dns requests are forwarded to this port yourself. no one's doing it for you bestie 😭
  • -n auto|external_ip β€” the IP address to return in NS responses. default is to return the address used as destination in the query. if external_ip is auto, iodined will use the opendns.com DNS service to retrieve the external IP of the host and use that for NS responses.
  • -b dnsport β€” if this port is specified, all incoming requests not inside the tunnel domain will be forwarded to this port on localhost, to be handled by a real dns. if 'listen_ip' does not include localhost, this 'dnsport' can be the same as 'port'.
Note: the forwarding is not fully transparent, and not advised for use in production environments. fr fr, don't do it in prod 🚩
  • -i max_idle_time β€” make the server stop itself after max_idle_time seconds if no traffic have been received. this should be combined with systemd or upstart on demand activation for being effective. it's giving "I'm leaving if nobody's talking to me" πŸ’€

🧚 Arguments 🧚

  • tunnel_ip[/netmask] β€” this is the server's ip address on the tun interface. the client will be given the next ip number in the range. it is recommended to use the 10.0.0.0 or 172.16.0.0 ranges. the default netmask is /27, and can be overridden by specifying it here. using a smaller network will limit the number of concurrent users. so like, plan accordingly bestie 🫢
  • topdomain β€” the dns traffic is expected to arrive as queries for subdomains under 'topdomain'. this is normally a subdomain to a domain you own. use a short domain name to get better throughput. this argument must be the same on both the client and the server. queries for domains other than 'topdomain' will be forwarded when the -b option is given, otherwise they will be dropped. the topdomain can start with * which will allow all domains ending with the same suffix. wildcard slay 🌟

πŸ”₯ EXAMPLES πŸ”₯

see the README file for both a quick test scenario, and a detailed description of real-world deployment. it's got the whole lore iykyk πŸ“–

πŸ” SECURITY πŸ”

login is a relatively secure challenge-response MD5 hash, with the password never passing the wire. cute! BUT β€” all other data is NOT encrypted in any way 😭. the DNS traffic is also vulnerable to replay, injection and man-in-the-middle attacks, especially when iodined is used with the -c option. use of ssh or vpn tunneling is strongly recommended.

on both server and client, use iptables, pf or other firewalls to block all traffic coming in from the tun interfaces, except to the used ssh or vpn ports. like please actually do this πŸ™

🌈 ENVIRONMENT 🌈

πŸ’œ IODINED_PASS πŸ’œ

if the environment variable IODINED_PASS is set, iodined will use the value it is set to as password instead of asking for one. the -P option still has precedence. so -P wins the argument, periodt πŸ‘‘

πŸ”— SEE ALSO πŸ”—

iodine(8)

the README file in the source distribution contains some more elaborate information. go read it, it's worth it πŸ’–

πŸ’€ BUGS πŸ’€

file bugs at https://github.com/yarrick/iodine β€” github dot com slash yarrick slash iodine, go off πŸ›

🌸 AUTHORS 🌸

Erik Ekman <yarrick@kryo.se> and Bjorn Andersson <flex@kryo.se>. major contributions by Anne Bezemer. legends, all of them πŸ‘‘


and that's the whole page, bestie πŸŽ€ this was the User Manuals page for iodined, dated APR 2023 β€” like, vintage but still serving πŸ’… ok bye, go tunnel something πŸ¦‹

πŸ“¦ where this page comes from