How does iocaine work?

When asking “how does it work?”, we’ll need to distinguish between two parts: how iocaine can detect bots, and how does it generate an infinite maze of garbage?

How iocaine generates garbage

When starting up, iocaine loads its word list and training data, these will be used for garbage generation. Garbage generation is stateless, random, and stable - meaning that iocaine does not keep track of who visited what, it seeds its random number generator in a way that the same request will always produce the same result, as long as the configuration is unchanged. This way of generating randomness is not secure, but that isn’t what we’re looking for here: for iocaine’s purposes, a fast and stable random number generator works much better than a cryptographically secure one.

How the generated garbage looks, can be controlled via templates. A somewhat minimalist default template is provided, but the templating language is reasonably powerful, you can let your imagination go wild, and adjust it to your preferences.

How do bots end up in iocaine’s maze?

Originally, iocaine was purely about generating garbage, it was the job of the reverse proxy to figure out what to route to it, and it happily served garbage to anything that came its way. That is still the default mode of operation, but no longer the recommended way.

The other, more efficient option, is to set up a request handler script, and pipe almost everything through iocaine. If iocaine decides to handle the request itself, it returns a HTTP 200 response, which the reverse proxy should serve. If it decides that the request is legit, that it is not to be served garbage, it returns a HTTP 421 (Misdirected Request) to the reverse proxy. The reverse proxy should be configured to catch a 421 response, and serve the upstream resource instead.

As a quick example, this is how a very simple deployment would look with Caddy:

example.org {
  reverse_proxy 127.0.0.1:42069 {
    @fallback status 421
    handle_response @fallback {
      header content-type "text/plain"
      respond "ok" 200
    }
  }
}

The same thing for nginx would follow a similar pattern:

upstream iocaine {
  server 127.0.0.1:42069;
}
server {
  listen 0.0.0.0:80;

  location / {
    proxy_pass http://iocaine;
    proxy_cache off;
    proxy_intercept_errors on;
    error_page 421 = @fallback;
  }

  location @fallback {
    add_header content-type text/plain;
    return 200 "ok";
  }
}

In practice, you may need to do something a little bit more complicated - see the howtos for more detailed guides.