<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Patrick Elsen</title>
    <description>The latest articles on DEV Community by Patrick Elsen (@xfbs).</description>
    <link>https://dev.to/xfbs</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F27657%2F1c75da79-31f6-4fac-82d5-164568045ac5.jpeg</url>
      <title>DEV Community: Patrick Elsen</title>
      <link>https://dev.to/xfbs</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/xfbs"/>
    <language>en</language>
    <item>
      <title>How to make use of the GitLab CI for Rust Projects</title>
      <dc:creator>Patrick Elsen</dc:creator>
      <pubDate>Mon, 17 Oct 2022 13:26:04 +0000</pubDate>
      <link>https://dev.to/xfbs/how-to-make-use-of-the-gitlab-ci-for-rust-projects-4j1o</link>
      <guid>https://dev.to/xfbs/how-to-make-use-of-the-gitlab-ci-for-rust-projects-4j1o</guid>
      <description>&lt;p&gt;&lt;a href="https://gitlab.com" rel="noopener noreferrer"&gt;GitLab&lt;/a&gt; is an &lt;a href="https://gitlab.com/rluna-gitlab/gitlab-ce" rel="noopener noreferrer"&gt;open-source-core&lt;/a&gt; collaborative development platform that has project planning and continuous integration features built in. I like it, because it is very easy to use, and yet powerful. The free hosted version gives you a lot of awesome features, but you can even &lt;a href="https://about.gitlab.com/install/" rel="noopener noreferrer"&gt;self-host GitLab&lt;/a&gt;, as it is open-source and permissively licensed. In this series, I'm going to be showing you a few examples on how you can set it up so that you get the most out of it. Hopefully you will find it useful.&lt;/p&gt;

&lt;p&gt;In this article, I will show you how you can use GitLab to host your Rust project, complete with a working CI setup that will run your tests, build the project and publish documentation on every commit. If you like open-source software and don't like complicated CI systems, this article is for you.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can skip this article and go straight to &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example" rel="noopener noreferrer"&gt;the repository&lt;/a&gt; if you just want to see a minimal example.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Setting up the Project
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm assuming you already have a GitLab account. If you do not, you should &lt;a href="https://gitlab.com/users/sign_up" rel="noopener noreferrer"&gt;create one&lt;/a&gt;, they are free and you will get a lot of free perks with it, such as free access to some amount of CI runner minutes. You will also need to &lt;a href="https://docs.gitlab.com/ee/user/ssh.html" rel="noopener noreferrer"&gt;set up your SSH keys&lt;/a&gt; so you can push to it. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;We will need to create a new project to walk you through how to set up the CI to get the most out of it. When you log in to GitLab, you are typically greeted by your list of projects. You can either press the big blue &lt;em&gt;New Project&lt;/em&gt; button or press the little plus in the navigation bar up top and select &lt;em&gt;New project/repository&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmyr1kxdfrsxnbg14sq3y.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fmyr1kxdfrsxnbg14sq3y.png" alt="GitLab Logged In View"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you have found either one of these buttons, they should take you to the new project page. Here, GitLab will ask you if you want to create a blank project or from a template. You can select &lt;em&gt;Create blank project&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff4vkodax1v03gg9zts8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fff4vkodax1v03gg9zts8.png" alt="GitLab new project"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once you've selected that, it will ask you for a name for the project, and some other options. You can put in any name you like, I'm naming this one &lt;em&gt;Rust GitLab Example&lt;/em&gt;. Notice that it will fill in the URL for you, but you can also customize it. To make it easier to type, the URL should use lowercase characters and dashes rather than spaces. I have also deselected the &lt;em&gt;Initialize repository with README&lt;/em&gt; option, because I'll write one myself.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5f0qjnk74yd7w068uud.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu5f0qjnk74yd7w068uud.png" alt="GitLab new project settings"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When you are happy with your selection, hit the &lt;em&gt;Create project&lt;/em&gt; button and it should take you to the new, empty project page.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frisotbwcqr7s3oahij9x.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frisotbwcqr7s3oahij9x.png" alt="GitLab new project page"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Now, you've successfully setup a new GitLab project. In the next section, I'll show you how to put some Rust code into it and setup the CI to do it's magic.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a Rust Project
&lt;/h2&gt;

&lt;p&gt;Next up, we need new Rust project that we can push to GitLab. If you're doing this with your own Rust project, you'll obviously already have some code to push. I don't, so I'm going to write some placeholder code. As usual, start out by using Cargo to generate a new project:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ cargo new rust-gitlab-example


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Next, I add &lt;a href="https://docs.rs/clap" rel="noopener noreferrer"&gt;clap&lt;/a&gt; as a dependency to let me parse command-line arguments. As usual, &lt;code&gt;cargo add&lt;/code&gt; does this quickly.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ cargo add clap --features derive


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Then, I add some placeholder code. As I said, this is just an example to showcase the CI capabilities, feel free to use your own Rust project instead. I drop this into &lt;code&gt;src/main.rs&lt;/code&gt;:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;

&lt;span class="cd"&gt;//! # Rust GitLab Example&lt;/span&gt;
&lt;span class="cd"&gt;//!&lt;/span&gt;
&lt;span class="cd"&gt;//! This implements a little command-line utility which will print a greeting for&lt;/span&gt;
&lt;span class="cd"&gt;//! a specified name.&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// Command-line options&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Parser,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Name to use for greeting&lt;/span&gt;
    &lt;span class="nd"&gt;#[clap(long,&lt;/span&gt; &lt;span class="nd"&gt;short,&lt;/span&gt; &lt;span class="nd"&gt;default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Human"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="cd"&gt;/// Given a name, generate a greeting.&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;format!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Hello {name}!"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[test]&lt;/span&gt;
&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;greeting_works&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;assert_eq!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Mark"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s"&gt;"Hello Mark!"&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="nd"&gt;println!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nf"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="py"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can verify that everything works by running the unit tests:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ cargo test
running 1 test
test greeting_works ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out; finished in 0.00s


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;We can also make sure that the binary works, by running it with &lt;code&gt;cargo run&lt;/code&gt;.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

$ cargo run
Hello, Human!
$ cargo run -- --name Patrick
Hello, Patrick!


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;At this point, we should have some code that runs. Bonus points for having documentation comments and some unit tests. These are important because in the next section we'll be adding a CI pipeline job that will run the unit tests and publish the documentation. &lt;/p&gt;

&lt;h2&gt;
  
  
  Writing CI Configuration
&lt;/h2&gt;

&lt;p&gt;Now that we have some example code, we have to tell the GitLab CI system what it should do. We do this by creating a &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file in the repository with a configuration. This is fortunately not very difficult, but before I explain how this is done, let me quickly walk you through the basic concepts.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m1boaxif8z4g7aln697.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F5m1boaxif8z4g7aln697.png" alt="GitLab CI Pipeline overview"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The CI system uses the concepts of &lt;em&gt;jobs&lt;/em&gt; and &lt;em&gt;stages&lt;/em&gt;. Jobs belong to stages. Stages (and with them, all jobs that are part of them) run sequentially, in the order that you define them. All of the jobs that belong to a stage run in parallel, meaning at the same time. A run of all of the jobs and stages is called a &lt;em&gt;pipeline&lt;/em&gt;. If any of the jobs in a stage fails, the entire stage is marked as failing and the &lt;em&gt;CI pipeline&lt;/em&gt; run is marked as a failure. The entire &lt;em&gt;pipeline&lt;/em&gt; is launched whenever you push new code, tags, branches, create merge requests, or launch it manually.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;For advanced users, &lt;a href="https://docs.gitlab.com/ee/ci/directed_acyclic_graph/" rel="noopener noreferrer"&gt;GitLab also offers the ability to declare your CI jobs as a Directed Acyclic Graph&lt;/a&gt; to have your jobs run faster, which can be useful when you have a lot of them. You can also mark jobs as being allowed to fail, or only run conditionally (for example only when files in a certain folder have changed, which is useful when you're stuck with a big monorepo). This article barely scratches the surface of what the CI system can do, check out &lt;a href="https://docs.gitlab.com/ee/ci/pipelines/" rel="noopener noreferrer"&gt;the documentation&lt;/a&gt; if you want to know more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8hnipsdsxmeg0yvgp0o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fe8hnipsdsxmeg0yvgp0o.png" alt="GitLab CI Job"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;For the jobs, GitLab CI makes use of &lt;a href="https://en.wikipedia.org/wiki/Docker_(software)" rel="noopener noreferrer"&gt;Docker&lt;/a&gt;. Every job launches some docker container (that we can specify) and runs some commands inside of that container. If we create any new files within a job that we want to keep or that we want future jobs to have access to, we can create &lt;em&gt;artifacts&lt;/em&gt;, which are files or directories that are created as the output of a job and that future jobs can use as inputs. So to recap:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Name&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Job&lt;/td&gt;
&lt;td&gt;A few commands that run in a Docker container. Can produce some output in the form of artifacts. If any of the commands do not exit successfully, the job is considered failed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Stage&lt;/td&gt;
&lt;td&gt;A collection of jobs that run in parallel. If any of the jobs fail, the entire stage is considered failed.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pipeline&lt;/td&gt;
&lt;td&gt;A collection of stages that run sequentially. If any of the stages fail, the pipeline run is considered failed. Is triggered by pushing commits, tags, branches, creating merge requests or can be triggered manually.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Defining Stages
&lt;/h3&gt;

&lt;p&gt;For this example, we want to define three stages:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;test&lt;/strong&gt;, where we run unit tests,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;build&lt;/strong&gt;, where we compile the code,&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;publish&lt;/strong&gt;, where we publish the binaries and documentation.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You can start out by creating an empty &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file and adding the list of stages to it:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;stages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h3&gt;
  
  
  Defining Jobs
&lt;/h3&gt;

&lt;p&gt;Next, we have to define the jobs. We can start by creating the tests job, which will run the unit tests. This job does not produce any output, so we do not declare any artifacts here. We declare that this job is part of the &lt;em&gt;tests&lt;/em&gt; stage. We also declare that we want it to use the &lt;a href="https://hub.docker.com/_/rust" rel="noopener noreferrer"&gt;&lt;code&gt;rust&lt;/code&gt; Docker image&lt;/a&gt;. If any of the steps in the &lt;code&gt;script&lt;/code&gt; section fails, the entire job is treated as a failure. The &lt;code&gt;cargo test&lt;/code&gt; command will return a non-success status code on test failure, so that will do what we want. This is what we add to our &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;tests&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;test&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rust&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo test&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Looks easy, right? &lt;/p&gt;

&lt;p&gt;Next, we want to define the jobs where we actually build the binary, and while we're at it we'll also define a job where we build the documentation. These jobs are both part of the &lt;code&gt;build&lt;/code&gt; stage, so that they will run in parallel. One difference here to the tests job is that both of these jobs generate artifacts. The build job will export the generated binary as an artifact, while the documentation job will export the entire documentation folder. You can export multiple files or folders from a single job by adding more paths.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;a href="https://docs.gitlab.com/ee/ci/pipelines/job_artifacts.html" rel="noopener noreferrer"&gt;Job artifacts&lt;/a&gt; are files or folders that are created by jobs. They are stored and can either be used as dependencies for future jobs, or downloaded using the API. &lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;build:amd64&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rust&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo build --release&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;target/release/rust-gitlab-example&lt;/span&gt;

&lt;span class="na"&gt;rustdoc&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;build&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;rust&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;cargo doc&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;target/doc&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Finally, we want to publish the built binary and documentation. We can use the &lt;a href="https://docs.gitlab.com/ee/user/project/pages/" rel="noopener noreferrer"&gt;GitLab Pages&lt;/a&gt; feature to accomplish that. This is a feature of GitLab where they will host static files for you, free of charge. To make use of that, you need to create a CI job called &lt;code&gt;pages&lt;/code&gt; and it must export an artifact folder called &lt;code&gt;public&lt;/code&gt;. Whatever is in that folder, will then be publicly hosted at &lt;a href="https://xfbs.gitlab.io/rust-gitlab-example" rel="noopener noreferrer"&gt;xfbs.gitlab.io/rust-gitlab-example&lt;/a&gt;. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;GitLab Pages lets you host static content by declaring a CI job called &lt;code&gt;pages&lt;/code&gt;. By default, any artifacts in the &lt;code&gt;public/&lt;/code&gt; folder from that CI job will be hosted at &lt;code&gt;yourusername.gitlab.io/projectname&lt;/code&gt;. You can add a custom domain to host it at a more friendly domain through the UI. If your project is private, by default this hosted page is protected too, so it is also useful for publishing project-internal or confidential documentation.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Note in this stage that we are using a different Docker container (the &lt;a href="https://hub.docker.com/_/alpine" rel="noopener noreferrer"&gt;alpine&lt;/a&gt; container) because we do not need to build any Rust. We also declare some dependencies, this means that CI will fetch the artifacts from those jobs and extract them so that they are accessible in this job. In the job itself, we really just copy things to the right place and don't do anything else.&lt;/p&gt;

&lt;p&gt;One important note about this job: this job is only set to run when pushing to the &lt;code&gt;master&lt;/code&gt; branch. This is very important, because the published documentation should reflect what is on the master branch, and if this were to be omitted, this job would also run when creating private branches or merge requests.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;

&lt;span class="na"&gt;pages&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;stage&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;publish&lt;/span&gt;
  &lt;span class="na"&gt;image&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;alpine&lt;/span&gt;
  &lt;span class="na"&gt;dependencies&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;build:amd64&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;rustdoc&lt;/span&gt;
  &lt;span class="na"&gt;script&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mkdir -p public&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mv target/doc public/doc&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;mv target/release/rust-gitlab-example&lt;/span&gt;
  &lt;span class="na"&gt;artifacts&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;paths&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;public&lt;/span&gt;
  &lt;span class="na"&gt;only&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;master&lt;/span&gt;


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;You can find the full &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example/-/blob/master/.gitlab-ci.yml" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pushing it to GitLab
&lt;/h2&gt;

&lt;p&gt;Now, saving this file and pushing it up to GitLab, we can see that our pipeline is being correctly detected. In the left navigation, there is a little rocket icon labelled CI/CD, clicking this will get you to the list of &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example/-/pipelines" rel="noopener noreferrer"&gt;CI pipeline runs&lt;/a&gt;, and clicking on the &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example/-/pipelines/668089259" rel="noopener noreferrer"&gt;latest one&lt;/a&gt; will look something like this:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnd8ky6rcdrhbaj8fxkpy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fnd8ky6rcdrhbaj8fxkpy.png" alt="CI Pipeline status"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;You can click on any of the pipeline jobs to see the output of the script that was running. For example, if we want to see if there was any compiler warnings or issues when running the unit tests, we can click on the &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example/-/jobs/3179831780" rel="noopener noreferrer"&gt;&lt;code&gt;tests&lt;/code&gt; job&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaq16nj4acxew73id6y5.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fwaq16nj4acxew73id6y5.png" alt="CI tests job output"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;During the &lt;code&gt;pages&lt;/code&gt; job, we've published the documentation that we generated and we've published the binaries. We can check that this is published:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36scrdk49vh82xf683iy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F36scrdk49vh82xf683iy.png" alt="Generated rustdoc documentation"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;These things are available here, if you want to check them out yourself:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Binary: &lt;a href="https://xfbs.gitlab.io/rust-gitlab-example/rust-gitlab-example-amd64" rel="noopener noreferrer"&gt;xfbs.gitlab.io/rust-gitlab-example/rust-gitlab-example-amd64&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;Documentation: &lt;a href="https://xfbs.gitlab.io/rust-gitlab-example/doc/rust_gitlab_example" rel="noopener noreferrer"&gt;xfbs.gitlab.io/rust-gitlab-example/doc&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

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

&lt;p&gt;The GitLab repository that I created in this article is available &lt;a href="https://gitlab.com/xfbs/rust-gitlab-example" rel="noopener noreferrer"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;GitLab makes it very easy to create repositories, use off-the-shelf Docker containers to put together custom CI jobs. We were able to add CI capabilities including publishing binaries and documentation with only a handful of lines of configuration. The fact that it simply uses regular Docker containers also makes it easier to locally debug CI configuration. &lt;/p&gt;

&lt;p&gt;GitLab Pages makes hosting static things pleasant and is perfect for things like nightly builds, test coverage reports, or documentation. Some people even use it to host blogs or personal websites. For example, &lt;a href="https://passgen.it" rel="noopener noreferrer"&gt;passgen.it&lt;/a&gt;, my password generator with a Regex-like syntax, is hosted by GitLab Pages with a custom domain, and the releases (binaries, tarballs, debian packages) are generated by the CI on every commit for all platforms.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>hosting</category>
      <category>static</category>
      <category>ci</category>
    </item>
    <item>
      <title>Generating prime numbers with Python and Rust</title>
      <dc:creator>Patrick Elsen</dc:creator>
      <pubDate>Tue, 11 Oct 2022 13:58:53 +0000</pubDate>
      <link>https://dev.to/xfbs/generating-prime-numbers-with-python-and-rust-4663</link>
      <guid>https://dev.to/xfbs/generating-prime-numbers-with-python-and-rust-4663</guid>
      <description>&lt;p&gt;The other day, I helped a friend with some &lt;a href="https://projecteuler.net"&gt;Project Euler&lt;/a&gt; problems. Those are little programming puzzles that involve maths and coding. I am really quite fond of them, and I recommend you to try some if you want to hone your skills and you are not afraid of trying something a bit difficult.&lt;/p&gt;

&lt;p&gt;One thing that comes up in some of these challenges is needing &lt;a href="https://en.wikipedia.org/wiki/Prime_number"&gt;prime numbers&lt;/a&gt;. As the challenges are all about writing code, it means needing to implement a prime number generator.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;A prime number is a natural number that is only divisible by 1 and itself. Some examples are: 2, 3, 7, 11, 13, 17, and 19.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;There are quite a few strategies that can be used to generate them, and in fact quite a few more efficient than the one I'm going to discuss here. The point of this is not to find the best strategy, but rather to see how it can be implemented well and optimized.&lt;/p&gt;

&lt;h2&gt;
  
  
  Generating prime numbers up to one million
&lt;/h2&gt;

&lt;p&gt;This is perhaps the most naive solution for generating prime numbers up to on million in Python. In this solution, we simply iterate through numbers up to one million, and then try to see if they are divisible by anything other than 1 and itself.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;divisor&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_prime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This solution is incredibly inefficient, it takes forever to finish. We can do a lot better than this. There is three optimizations that we can implement:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;We don't even need to check even numbers, because we know that they are divisible by two. So we start our primes list with &lt;code&gt;[2]&lt;/code&gt; and then skip over all even candidate numbers in the first place. This means less candidates to try.&lt;/li&gt;
&lt;li&gt;All positive natural numbers are either prime or the product of (zero) or more primes. This means that instead of checking all candidate primes for divisibility by &lt;code&gt;[2..candidate-1]&lt;/code&gt;, we can simply check them for divisibility by the primes we have already found. This means less division tests.&lt;/li&gt;
&lt;li&gt;We only need to check for divisibility by primes up to &lt;code&gt;sqrt(candidate)&lt;/code&gt;, because for a candidate &lt;code&gt;c&lt;/code&gt; to be divisible by &lt;code&gt;a&lt;/code&gt;, it means there exists a solution for the formula 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;c=a⋅bc = a \cdot b&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;c&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;a&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mbin"&gt;⋅&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord mathnormal"&gt;b&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
. If a is larger than the square root, &lt;code&gt;b&lt;/code&gt; must be smaller than the square root. For this reason, it is sufficient to check for divisors up to the square root. This also means that we need less division tests.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;With these optimisations in place, our code looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="nn"&gt;math&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;sqrt&lt;/span&gt;

&lt;span class="n"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;

&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="nb"&gt;range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;True&lt;/span&gt;
    &lt;span class="n"&gt;square_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;sqrt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;prime&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;num&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;prime&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="bp"&gt;False&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;prime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;square_root&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_prime&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;num&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The runtime of this solution improved to only taking about 940ms on my machine, demonstrating that these optimisations have massively improved the implementation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementing it in Rust
&lt;/h2&gt;

&lt;p&gt;I will translate the algorithm into Rust here to show you what it would look like and how well it performs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I have to say that this is kind of cheating, because Rust is a compiled language, which means that the compiler has optimization opportunities that an interpreted language such as Python does not have.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Creating a new, empty Rust project with &lt;code&gt;cargo new primes&lt;/code&gt;, we can translate the Python version into Rust, only making use of iterators to sift through the list of primes to try dividing.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1000000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;square_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sqrt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt;
            &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.take_while&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;square_root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.all&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="nf"&gt;.push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What we do here is very similar to what we did in the Python version:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;We start out with an array of primes, pre-filled with the first prime,&lt;/li&gt;
&lt;li&gt;We iterate through the numbers 3 up to our maximum,&lt;/li&gt;
&lt;li&gt;For every candidate, we determine the square root. If none of the primes up to the square root of the candidate are a divisor, we consider the candidate to be prime and append it to the list.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One difference to note here: running this in release mode (using &lt;code&gt;cargo run --release&lt;/code&gt;) is so fast that it only takes about 30ms to generate one million primes. In the time that Python can generate on million primes, Rust can generate 20 million primes. This is to be expected, because Rust can take advantage of compilation.&lt;/p&gt;

&lt;h2&gt;
  
  
  Introducing Parallelism
&lt;/h2&gt;

&lt;p&gt;These solutions so far have been lacking in one aspect: they have not been able to take advantage of multiple CPU cores. How hard would it be to take the current Rust solution and introduce some parallelism?&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.rs/rayon"&gt;rayon&lt;/a&gt; crate in Rust is designed to help with exactly that: making it easy to write code in a multi-threaded way. I have never worked with it, so let's give it a go.&lt;/p&gt;

&lt;p&gt;We can get started by adding rayon to the list of dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add rayon
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, rayon gives us some interesting primitives to work with. For example, any Rust code that uses iterators can be transformed into running in parallel by replacing &lt;code&gt;.iter()&lt;/code&gt; with &lt;code&gt;.par_iter()&lt;/code&gt;. Behind the scenes, rayon handles starting a thread pool, dividing up the work, and waiting for the threads to finish. &lt;/p&gt;

&lt;p&gt;For example, we could replace the iterator-based code that we use to check if a number is divisible by some primes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rayon&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;is_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt;
    &lt;span class="nf"&gt;.par_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="nf"&gt;.filter&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;square_root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="nf"&gt;.all&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;However, doing this is actually bad for performance. This iteration walks the list of primes linearly, and as such it is actually very fast already (good &lt;a href="https://en.wikipedia.org/wiki/Locality_of_reference"&gt;locality&lt;/a&gt;, friendly for CPU caches). Breaking this down to run on multiple threads does more harm than good, and brings our runtime from 30ms up to 17s. Can we find a better optimization opportunity?&lt;/p&gt;

&lt;p&gt;We have to try to break down the algorithm into bigger chunks. So rather than breaking down the loop where we test individual divisors, we can break it down into testing different candidate primes in multiple threads.&lt;/p&gt;

&lt;p&gt;One thing we must fix before doing that is dealing with  mutability. Our list of primes is used for two purposes: we use it to check candidate numbers for being prime by checking divisibility (read-only usage) and we append new primes to the end of it (read-write usage). The issue here is that when we work multi-threaded, it becomes problematic to use the same data in both a read-only and read-write manner. The easy solution to that is splitting that up into two separate variables: the &lt;code&gt;primes&lt;/code&gt; array is now only used read-only, and we introduce a new &lt;code&gt;new_primes&lt;/code&gt; array that we append new primes to. Occasionally we append the &lt;code&gt;new_primes&lt;/code&gt; array onto &lt;code&gt;primes&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;Here is what all of this looks like together. Note that I've had to import rayon's prelude (importing that gives us access to all of rayon's iterator adapters) and we are using &lt;code&gt;par_extend()&lt;/code&gt;, which will extend an array in parallel. So in this implementation, we will test different candidates for primality at the same time.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;rayon&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;prelude&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;];&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;1_000_000&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;loop&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;new_primes&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[];&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;last_prime&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="nf"&gt;.last&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.unwrap&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;last_prime&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;maximum&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;new_primes&lt;/span&gt;&lt;span class="nf"&gt;.par_extend&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;last_prime&lt;/span&gt;&lt;span class="o"&gt;..&lt;/span&gt;&lt;span class="n"&gt;last_prime&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.into_par_iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.filter&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;square_root&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;f64&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="nf"&gt;.sqrt&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;u64&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="n"&gt;primes&lt;/span&gt;
                    &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
                    &lt;span class="nf"&gt;.take_while&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;square_root&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                    &lt;span class="nf"&gt;.all&lt;/span&gt;&lt;span class="p"&gt;(|&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="n"&gt;candidate&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt; &lt;span class="n"&gt;p&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;})&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;primes&lt;/span&gt;&lt;span class="nf"&gt;.append&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;new_primes&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This implementation cuts down the time it takes to compute primes up to one million down to about 11ms on my machine.&lt;/p&gt;

&lt;h2&gt;
  
  
  Results
&lt;/h2&gt;

&lt;p&gt;Here are the raw results from the rest runs:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Algorithm&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Time (relative change)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Naive (1 million)&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;24m7s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Better (1 million)&lt;/td&gt;
&lt;td&gt;Python&lt;/td&gt;
&lt;td&gt;940ms (153936% faster)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Better (1 million)&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;30ms (3133% faster)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Parallel (1 million)&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;11ms (273% faster)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;We have learned that it is quite easy to generate prime numbers in both Python and Rust. Generating them quickly takes a little bit of experimentation. Rayon helps a lot in making things multi-threaded, it's almost magic. But we still had to identify the best places to introduce parallelism, and we had to change the algorithm slightly. &lt;/p&gt;

&lt;p&gt;Just for fun, I decided to see how many primes I could generate with the Rayon implementation. After running it for 2m25s, it went up to the prime 5222275627, which I thought was quite impressive. Running it for longer, about 30m (close to how long the naive Python implementation took to generate primes up to one million), it was able to come up with the prime 41778204911.&lt;/p&gt;

&lt;p&gt;It was a lot of fun to figure out how to generate primes quickly. I hope that you learned something, maybe you will find a use-case for &lt;a href="https://docs.rs/rayon"&gt;rayon&lt;/a&gt; yourself. It was a pleasure to work with.&lt;/p&gt;

</description>
      <category>primes</category>
      <category>math</category>
      <category>rust</category>
      <category>fun</category>
    </item>
    <item>
      <title>Writing a toy DNS Server in Rust using Trust DNS</title>
      <dc:creator>Patrick Elsen</dc:creator>
      <pubDate>Sun, 02 Oct 2022 21:35:13 +0000</pubDate>
      <link>https://dev.to/xfbs/writing-a-dns-server-in-rust-1gpn</link>
      <guid>https://dev.to/xfbs/writing-a-dns-server-in-rust-1gpn</guid>
      <description>&lt;p&gt;Ever wondered how you can write a &lt;a href="https://en.wikipedia.org/wiki/Domain_Name_System"&gt;DNS server&lt;/a&gt; in Rust? No? Well, too bad, I'm telling you anyways. But don't worry, this is going to be a fun one. &lt;/p&gt;

&lt;p&gt;Before we actually get started, I must perhaps first explain what DNS is. If you really want to understand it, I think you should check out Julia Evans' &lt;a href="https://jvns.ca/blog/2022/04/26/new-zine--how-dns-works-/"&gt;DNS Zine&lt;/a&gt; post, she does a far better job at explaining it than I ever could. But if you don't have enough time, here's the TL;DR: &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;DNS is the protocol that is used to answer questions like &lt;em&gt;What's the &lt;a href="https://en.wikipedia.org/wiki/IP_address"&gt;IP address&lt;/a&gt; of &lt;code&gt;google.com&lt;/code&gt;&lt;/em&gt;? Usually, when you open a website in your browser, you use domain names. In &lt;code&gt;https://dev.to&lt;/code&gt;, the &lt;code&gt;dev.to&lt;/code&gt; is a domain name. Other domain names you might know are &lt;code&gt;youtube.com&lt;/code&gt; or &lt;code&gt;lobste.rs&lt;/code&gt;. But in order for your browser (or any software on your computer, for that matter) to establish a connection, it needs to know which IP address to talk to. An IP address is something like &lt;code&gt;172.217.16.206&lt;/code&gt;: basically just a few numbers that are enough to send your request to the right place. Very similar to a phone number or a physical address. Using the DNS protocol, your browser sends a request to get the IP addresses for some domain name, and then it gets a response with the answers.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;If you are using Linux or macOS (or you have WSL2 enabled on your Windows 10 machine), you can use the DNS protocol to look up the IP addresses for &lt;code&gt;dev.to&lt;/code&gt; using the &lt;code&gt;dig&lt;/code&gt; tool:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig +short dev.to
151.101.194.217
151.101.2.217
151.101.66.217
151.101.130.217
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this example, we are request the IPv4 address records of &lt;code&gt;dev.to&lt;/code&gt;, but you can use the DNS protocol to query other stuff as well. We'll get to that in a bit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting up a new Rust project
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;I'm writing this blog post as I'm writing this DNS server, and if you want to you can follow along, but all of the code also lives on &lt;a href="https://github.com/xfbs/dnsfun"&gt;xfbs/dnsfun&lt;/a&gt; if you just want to clone it and try it out for yourself.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;First, we must setup a new Rust project. Rust uses &lt;a href="https://doc.rust-lang.org/cargo/"&gt;cargo&lt;/a&gt;, a package manager, build system, documentation generation tool, and so much more. If you haven't set up Rust, check out the instructions at &lt;a href="https://rustup.rs/"&gt;rustup&lt;/a&gt; to get started. We use the &lt;code&gt;cargo new&lt;/code&gt; subcommand to &lt;a href="https://github.com/xfbs/dnsfun/commit/12a2b83a1b568eec4b05fd831e70220bb4e5b32a"&gt;create a new Rust project&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo new dnsfun
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates the folder &lt;code&gt;dnsfun&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates a default code file at &lt;code&gt;dnsfun/src/main.rs&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Creates a default config at &lt;code&gt;dnsfun/Cargo.toml&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Adding dependencies
&lt;/h2&gt;

&lt;p&gt;Once the project exists, we have to add dependencies. Usually, I add them one-by-one, when I need them. But for this project, I already know what I'm going to use, so I add the ones I know I will need upfront. &lt;/p&gt;

&lt;p&gt;Normally, we would add these dependencies manually to the &lt;code&gt;Crates.toml&lt;/code&gt; file, but &lt;code&gt;cargo&lt;/code&gt; has a helpful subcommand to help us do that.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cargo add clap --features derive,env
cargo add tokio --features macros,rt-multi-thread,net
cargo add trust-dns-server
cargo add tracing
cargo add tracing-subscriber
cargo add async-trait
cargo add anyhow
cargo add thiserror
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is &lt;a href="https://github.com/xfbs/dnsfun/commit/5a9929e58349542b5d230dd70191816751364a86"&gt;add the dependencies&lt;/a&gt; to the &lt;code&gt;[dependencies]&lt;/code&gt; section in the &lt;code&gt;Cargo.toml&lt;/code&gt; file. The dependencies are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/tokio"&gt;tokio&lt;/a&gt;, a very powerful async library,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/clap"&gt;clap&lt;/a&gt;, a library used to parse command-line options,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/trust-dns-server"&gt;trust-dns-server&lt;/a&gt;, a library that implements a DNS server,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/tracing"&gt;tracing&lt;/a&gt;, which lets us do logging and tracing of what's going on,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/tracing-subscriber"&gt;tracing-subscriber&lt;/a&gt;, which lets us print logs and traces to the standard output,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/async-trait"&gt;async-trait&lt;/a&gt;, which helps us create async trait methods,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/anyhow"&gt;anyhow&lt;/a&gt;, a package that provides a generic error type,&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docs.rs/thiserror"&gt;thiserror&lt;/a&gt;, a package that lets us easily define our own error types.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;One thing you may have noticed is the features thing — in Rust, &lt;a href="https://doc.rust-lang.org/cargo/reference/features.html"&gt;dependencies often have optional features that are only built if requested&lt;/a&gt;. If you read the documentation for a crate, it will tell you which features you need to enable to use certain things. This just helps keep compile times low.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding boilerplate code
&lt;/h2&gt;

&lt;p&gt;With these dependencies in place, we can start with a very small boilerplate. Rust is not very verbose, it does not need some intricate setup or folder structure. Since we do want to use async, we need to initialize an async runtime, and because we want some amount of logging we need to initialize the &lt;a href="https://docs.rs/tracing_subscriber"&gt;tracing_subscriber&lt;/a&gt; crate. This is accomplished like this in the &lt;a href="https://github.com/xfbs/dnsfun/commit/b8324ce7a577e599b077f032ccf386eb902ba180"&gt;src/main.rs&lt;/a&gt; file.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;#[tokio::main]&lt;/code&gt; is a &lt;a href="https://docs.rs/tokio/latest/tokio/attr.main.html"&gt;macro from the tokio crate&lt;/a&gt; that automatically generates the code needed to start the runtime. We can use this because we turned on the &lt;code&gt;macros&lt;/code&gt; feature of tokio.&lt;/p&gt;

&lt;h2&gt;
  
  
  Adding command-line options
&lt;/h2&gt;

&lt;p&gt;There's some configuration options that the DNS server needs that we don't want to hard-code. So instead, we use command-line options to set them at runtime. We could have also used a configuration file, but that seemed overkill. So we &lt;a href="https://github.com/xfbs/dnsfun/commit/d9daafea4374a1d81d84adfc1f6e402574b14db7"&gt;create a new file, &lt;code&gt;src/options.rs&lt;/code&gt;&lt;/a&gt;, with this content:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="nd"&gt;#[derive(Parser,&lt;/span&gt; &lt;span class="nd"&gt;Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Options&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// UDP socket to listen on.&lt;/span&gt;
    &lt;span class="nd"&gt;#[clap(long,&lt;/span&gt; &lt;span class="nd"&gt;short,&lt;/span&gt; &lt;span class="nd"&gt;default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"0.0.0.0:1053"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;env&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DNSFUN_UDP"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;udp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="cd"&gt;/// TCP socket to listen on.&lt;/span&gt;
    &lt;span class="nd"&gt;#[clap(long,&lt;/span&gt; &lt;span class="nd"&gt;short,&lt;/span&gt; &lt;span class="nd"&gt;env&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DNSFUN_TCP"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Vec&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;SocketAddr&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

    &lt;span class="cd"&gt;/// Domain name&lt;/span&gt;
    &lt;span class="nd"&gt;#[clap(long,&lt;/span&gt; &lt;span class="nd"&gt;short,&lt;/span&gt; &lt;span class="nd"&gt;default_value&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"dnsfun.dev"&lt;/span&gt;&lt;span class="nd"&gt;,&lt;/span&gt; &lt;span class="nd"&gt;env&lt;/span&gt; &lt;span class="nd"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DNSFUN_DOMAIN"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;String&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For explanation, the DNS protocol usually uses either UDP or TCP. Typically, UDP is preferred, but because there is a fixed maximum size for UDP packets, TCP can be used as fallback for when the response would be too large. We've declared three command-line options here:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;--udp &amp;lt;socket&amp;gt;&lt;/code&gt; sets the sockets (address and port to listen on) for UDP packets. If nothing is specified, it defaults to &lt;code&gt;0.0.0.0:1053&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--tcp &amp;lt;socket&amp;gt;&lt;/code&gt; sets the sockets to listen for TCP connections. There is no default specified, so by default it won't listen to TCP connections.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;--domain &amp;lt;domain&amp;gt;&lt;/code&gt; sets the domain that we want to serve DNS requests for, it defaults to &lt;code&gt;dnsfun.dev&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The &lt;a href="https://docs.rs/clap"&gt;clap&lt;/a&gt; crate with the &lt;code&gt;derive&lt;/code&gt; feature is very neat: we have a full declarative command-line parser in only 20 or so lines of Rust. This is all made possible because of the &lt;code&gt;#[derive(Parser)]&lt;/code&gt; — that turns a Rust struct into a definition for command-line options. Any member of the field becomes a flag. If you add a field that is &lt;code&gt;Option&amp;lt;String&amp;gt;&lt;/code&gt;, it becomes an optional flag. If you have a field that is a &lt;code&gt;Vec&amp;lt;String&amp;gt;&lt;/code&gt;, you can pass it multiple times.&lt;/p&gt;

&lt;h2&gt;
  
  
  Creating a dummy Request Handler
&lt;/h2&gt;

&lt;p&gt;In order for us to serve DNS requests, we need some code that generates the response for each request. The crate that we are using, &lt;a href="https://docs.rs/trust-dns-server"&gt;trust-dns-server&lt;/a&gt;, calls this a &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;We start by creating our own dummy implementation of a RequestHandler, just so we can get something to compile, and then we will get back to it and actually fill out the code.&lt;/p&gt;

&lt;p&gt;We'll put this into a separate module, just to keep things somewhat tidy. So, we &lt;a href="https://github.com/xfbs/dnsfun/commit/f17d3ea9a06b703d2399581a62cc78f87dcad82f"&gt;create a &lt;code&gt;src/handler.rs&lt;/code&gt; with the following content&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="k"&gt;crate&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;trust_dns_server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;server&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;RequestHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;ResponseInfo&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="cd"&gt;/// DNS Request Handler&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;

&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Create new handler from command-line options.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;from_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;Self&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nd"&gt;#[async_trait::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;RequestHandler&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;handle_request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;_response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ResponseInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nd"&gt;todo!&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'll walk you through what is going on here. First, we are importing a few things, such as the &lt;code&gt;Options&lt;/code&gt; struct that holds the command-line options and some types we need for the DNS server.&lt;/p&gt;

&lt;p&gt;Next, we define a struct called &lt;code&gt;Handler&lt;/code&gt;. With the &lt;code&gt;#[derive(Clone, Debug)]&lt;/code&gt;, we are asking the Rust compiler to implement &lt;a href="https://doc.rust-lang.org/std/clone/trait.Clone.html"&gt;Clone&lt;/a&gt; for us, which gives us a &lt;code&gt;.clone()&lt;/code&gt; method, and to implement &lt;a href="https://doc.rust-lang.org/std/fmt/trait.Debug.html"&gt;Debug&lt;/a&gt;, which generates code to let us pretty-print it for debugging purposes. &lt;/p&gt;

&lt;p&gt;In the &lt;code&gt;impl Handler&lt;/code&gt; block, we define a function &lt;code&gt;from_options&lt;/code&gt; to create a Handler struct from some parsed command-line options. If you are used to classes, this is roughly equivalent to a constructor.&lt;/p&gt;

&lt;p&gt;Finally, we implement the &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt; trait for our Handler struct. To implement a trait, we must to define all of the functions that the trait requires. If you are used to classes, you can think of traits like interfaces or abstract base classes. Any struct you create can implement as many traits as you like. You can also create your own traits and implement them for any structs you like, the system is very flexible.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You might be a bit confused here — why does our implementation of the trait look so different from the trait definition in the documentation for &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt;? What's with all those weird lifetimes? There is some macro magic going on here. On that documentation page, if you click on &lt;a href="https://docs.rs/trust-dns-server/0.22.0/src/trust_dns_server/server/request_handler.rs.html#139-151"&gt;source&lt;/a&gt; in the top right, you will see that we've implemented the trait exactly like how it was specified, but the docs show the version of the trait that's been automatically converted into a non-async method.&lt;/p&gt;

&lt;p&gt;Right now, &lt;a href="https://smallcultfollowing.com/babysteps/blog/2019/10/26/async-fn-in-traits-are-hard/"&gt;you cannot use async methods in trait methods in Rust&lt;/a&gt;, but the &lt;code&gt;#[async-trait::async-trait]&lt;/code&gt; macro makes that possible still. This is a known quirk in the compiler, and the compiler itself will tell you to use &lt;a href="https://docs.rs/async-trait"&gt;async-trait&lt;/a&gt; instead. Eventually, async methods in traits will be stabilized, but thanks to the powerful macro system we can polyfill that ourselves.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;In the &lt;code&gt;handle_request&lt;/code&gt; method, you can see that it is generic over &lt;code&gt;R&lt;/code&gt;: it accepts anything that implements &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.ResponseHandler.html"&gt;ResponseHandler&lt;/a&gt;. This is because sending out the response depends on the protocol being used (DNS can work over UDP, TCP, &lt;a href="https://en.wikipedia.org/wiki/DNS_over_TLS"&gt;TLS&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/DNS_over_HTTPS"&gt;HTTPS&lt;/a&gt;, etc). So the actual response handler type will depend on which protocol the request came in on. Also, you can see that we've put a &lt;a href="https://doc.rust-lang.org/std/macro.todo.html"&gt;&lt;code&gt;todo!()&lt;/code&gt;&lt;/a&gt; where the implementation should be, this means that it will just crash because it is not implemented.&lt;/p&gt;

&lt;h2&gt;
  
  
  Launching DNS Server
&lt;/h2&gt;

&lt;p&gt;Now that we have a dummy &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt; in place, we can &lt;a href="https://github.com/xfbs/dnsfun/commit/a65a1d8a61154d9c2b5693087fe44972ea4f86db"&gt;get back to the main method and actually start the DNS server&lt;/a&gt;. To do so, we change the &lt;code&gt;src/main.rs&lt;/code&gt; to import the handler struct and create a &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/struct.ServerFuture.html"&gt;ServerFuture&lt;/a&gt; with the right listeners and then await it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;anyhow&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;clap&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Parser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;options&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;time&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;tokio&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;net&lt;/span&gt;&lt;span class="p"&gt;::{&lt;/span&gt;&lt;span class="n"&gt;TcpListener&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;UdpSocket&lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;use&lt;/span&gt; &lt;span class="nn"&gt;trust_dns_server&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ServerFuture&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cd"&gt;/// Timeout for TCP connections.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;TCP_TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Duration&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Duration&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_secs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="nd"&gt;#[tokio::main]&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="nf"&gt;main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nn"&gt;tracing_subscriber&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;fmt&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;init&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;options&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;handler&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Handler&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_options&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// create DNS server&lt;/span&gt;
    &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;ServerFuture&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// register UDP listeners&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;udp&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="py"&gt;.udp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="nf"&gt;.register_socket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;UdpSocket&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;udp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// register TCP listeners&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tcp&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="py"&gt;.tcp&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="nf"&gt;.register_listener&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TcpListener&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;bind&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;tcp&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;TCP_TIMEOUT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// run DNS server&lt;/span&gt;
    &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="nf"&gt;.block_until_done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(())&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The first thing you might spot here is that we've defined a constant, &lt;code&gt;TCP_TIMEOUT&lt;/code&gt;. This timeout is to prevent an attacker from creating a ton of TCP connections and then just letting them sit idle. It's good practice to give these constants a name so that we can add a &lt;a href="https://doc.rust-lang.org/rust-by-example/meta/doc.html"&gt;documentation comment&lt;/a&gt; (starts with three slashes rather than two).&lt;/p&gt;

&lt;p&gt;You can see how we are constructing a &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/struct.ServerFuture.html"&gt;ServerFuture&lt;/a&gt;, this is the DNS server. If you look at the documentation for the &lt;a href="https://docs.rs/trust-dns-server/latest/trust_dns_server/struct.ServerFuture.html#method.new"&gt;&lt;code&gt;new&lt;/code&gt; method&lt;/a&gt;, you can see that it needs a handler which implements &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt;. We have previously implemented that for our own &lt;code&gt;Handler&lt;/code&gt;. So when we create the &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/struct.ServerFuture.html"&gt;ServerFuture&lt;/a&gt;, we have to pass it an instance of our Handler. This trait system makes software very composable: the trust-dns-server crate hasn't hardcoded the responder, but they let us put our own logic into it simply by implementing the right trait.&lt;/p&gt;

&lt;p&gt;We're also finally using the command-line options by registering the appropriate listeners. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Something you might notice is that there is &lt;code&gt;.await&lt;/code&gt; in some places but not in others. Any time we call an async functions, we have to &lt;code&gt;.await&lt;/code&gt; it to get the result. But not all functions we call need to be async: &lt;a href="https://rust-lang.github.io/async-book/01_getting_started/02_why_async.html"&gt;only those functions that might block at some point&lt;/a&gt;. For example, opening a &lt;a href="https://docs.rs/tokio/latest/tokio/net/struct.UdpSocket.html"&gt;UdpSocket&lt;/a&gt; might block, because we have to wait for the operating system to give us a response, so that needs to be async. But creating a Handler struct from command-line options cannot block, because we have all the data we need (no need to wait for anything from disk). If this async stuff doesn't make sense to you right now, I might make a future blog post explaining it some more.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Running the DNS server
&lt;/h2&gt;

&lt;p&gt;At this point, we can already launch our DNS server. It is functional, except that any time we actually try to respond to a DNS packet, we will crash because of the &lt;code&gt;todo!()&lt;/code&gt;. But that's okay, let's try it out!&lt;/p&gt;

&lt;p&gt;We can use &lt;code&gt;cargo run -- &amp;lt;options&amp;gt;&lt;/code&gt; to run it. The double dashes are needed to separate options for cargo run (before them) from options for the program (after them).&lt;/p&gt;

&lt;p&gt;First, we can check out the automatically generated command-line options that we get from clap. If we pass the &lt;code&gt;--help&lt;/code&gt; argument to our program, we will get a help text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ cargo run -- --help
Usage: dnsfun [OPTIONS]

Options:
  -u, --udp &amp;lt;UDP&amp;gt;        UDP socket to listen on [env: DNSFUN_UDP=] [default: 0.0.0.0:1053]
  -t, --tcp &amp;lt;TCP&amp;gt;        TCP socket to listen on [env: DNSFUN_TCP=]
  -d, --domain &amp;lt;DOMAIN&amp;gt;  Domain name [env: DNSFUN_DOMAIN=] [default: dnsfun.dev]
  -h, --help             Print help information
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sweet, it tells us what the flags are, what they mean (this is parsed from the documentation string in the &lt;code&gt;Options&lt;/code&gt; struct), any default values and environment values that can be set.&lt;/p&gt;

&lt;p&gt;To run our DNS server, we need two terminals. In the one terminal, we run the server itself. To get a better idea of what is going on, &lt;a href="https://docs.rs/tracing-subscriber/latest/tracing_subscriber/fmt/index.html#filtering-events-with-environment-variables"&gt;we can set the &lt;code&gt;RUST_LOG&lt;/code&gt; environment value to &lt;code&gt;trace&lt;/code&gt;&lt;/a&gt;, which turns on verbose logging of the tracing-subscriber. In the other terminal, we use &lt;code&gt;dig&lt;/code&gt; to make a request to our DNS server. Here's what it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ RUST_LOG=trace cargo run
2022-10-02T08:32:31.013539Z TRACE mio::poll: registering event source with poller: token=Token(0), interests=READABLE | WRITABLE    
2022-10-02T08:32:31.013657Z DEBUG trust_dns_server::server::server_future: registering udp: PollEvented { io: Some(UdpSocket { addr: 0.0.0.0:1053, fd: 6 }) }
2022-10-02T08:32:34.149745Z DEBUG trust_dns_server::server::server_future: received udp request from: 127.0.0.1:51997
2022-10-02T08:32:34.150111Z TRACE trust_dns_proto::rr::record_data: reading OPT
2022-10-02T08:32:34.150249Z DEBUG trust_dns_server::server::server_future: request:30324 src:UDP://127.0.0.1#51997 type:QUERY dnssec:false QUERY:test.com.:A:IN qflags:RD,AD
thread 'tokio-runtime-worker' panicked at 'not yet implemented', src/handler.rs:27:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the other terminal:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig @127.0.0.1 -p 1053 test.com
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So far, we can receive UDP DNS requests! But we obviously can't respond to them. We've gotten command-line parsing essentially for free with &lt;a href="https://docs.rs/clap"&gt;clap&lt;/a&gt;, gotten logging basically for free with &lt;a href="https://docs.rs/tracing-subscriber"&gt;tracing_subscriber&lt;/a&gt;, and a DNS server implementation for free from &lt;a href="https://docs.rs/trust-dns-server"&gt;trust-dns-server&lt;/a&gt;. Now comes the interesting part, where we fill in our request handler.&lt;/p&gt;

&lt;h2&gt;
  
  
  Handling Requests, for real this time
&lt;/h2&gt;

&lt;p&gt;Now, we have to implement our handle_request method to do something useful. There's a lot of funny things we could implement, but to keep this blog post somewhat short, there's three things I want to implement:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;myip.dnsfun.dev&lt;/code&gt; should return the IP address of whomever is querying it.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;counter.dnsfun.dev&lt;/code&gt; should return how many requests it has served so far.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;&amp;lt;name&amp;gt;.hello.dnsfun.dev&lt;/code&gt; should return a greeting for the name.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This part is perhaps the hardest part, the DNS protocol offers a lot of terminology and possibilities that might be confusing. If you feel confused at times, don't worry — so did I. &lt;a href="https://github.com/xfbs/dnsfun/commit/5e8a7201b80db6e146d56693788eb8a295f406ec"&gt;Here's the entire diff of this step&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The very first thing I need to do to make this possible is that we need to add some more fields to the &lt;code&gt;Handler&lt;/code&gt; struct. To have a counter that is usable, we need some kind of atomic counter (it has to be atomic, because this whole thing is multithreaded). We will also need some help to route the requests for different subdomains.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="cd"&gt;/// DNS Request Handler&lt;/span&gt;
&lt;span class="nd"&gt;#[derive(Clone,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Request counter, incremented on every successful request.&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Arc&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;AtomicU64&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cd"&gt;/// Domain to serve DNS responses for (requests for other domains are silently ignored).&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;root_zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LowerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cd"&gt;/// Zone name for counter (counter.dnsfun.dev)&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;counter_zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LowerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cd"&gt;/// Zone name for myip (myip.dnsfun.dev)&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;myip_zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LowerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="cd"&gt;/// Zone name for hello (hello.dnsfun.dev)&lt;/span&gt;
    &lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="n"&gt;hello_zone&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;LowerName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I've decided to use an &lt;a href="https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU64.html"&gt;Arc&amp;lt;AtomicU64&amp;gt;&lt;/a&gt; for my atomic counter. This is a variable that I can atomically increment and load from multiple threads. I also store the zone names in here, this is so I can easily check for a query if it matches anything I care about.&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/trait.RequestHandler.html"&gt;RequestHandler&lt;/a&gt; trait wants the function to return a &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/struct.ResponseInfo.html"&gt;ResponseInfo&lt;/a&gt;, but there are cases where some error happens and we don't actually send a response. For this reason, I moved the actual logic into a different method, called &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L135"&gt;do_handle_request&lt;/a&gt;, which I call in this handler. If that returns an error, I log it and fake a &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/struct.ResponseInfo.html"&gt;ResponseInfo&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[async_trait::async_trait]&lt;/span&gt;
&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;RequestHandler&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;handle_request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;ResponseInfo&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// try to handle request&lt;/span&gt;
        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.do_handle_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="nd"&gt;error!&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Error in RequestHandler: {error}"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.set_response_code&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;ResponseCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;ServFail&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, in the &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L135"&gt;do_handle_response&lt;/a&gt; method, which is just a private method of the &lt;code&gt;Handler&lt;/code&gt; struct (similar to a private class method in OOP languages), I have to take a look at the request we got and decide what to do about it.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Handle request, returning ResponseInfo if response was successfully sent, or an error.&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_handle_request&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// make sure the request is a query&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.op_code&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nn"&gt;OpCode&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;InvalidOpCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.op_code&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// make sure the message type is a query&lt;/span&gt;
        &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.message_type&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="nn"&gt;MessageType&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Query&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;InvalidMessageType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.message_type&lt;/span&gt;&lt;span class="p"&gt;()));&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.myip_zone&lt;/span&gt;&lt;span class="nf"&gt;.zone_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.do_handle_request_myip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter_zone&lt;/span&gt;&lt;span class="nf"&gt;.zone_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.do_handle_request_counter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.hello_zone&lt;/span&gt;&lt;span class="nf"&gt;.zone_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.do_handle_request_hello&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.root_zone&lt;/span&gt;&lt;span class="nf"&gt;.zone_of&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="nf"&gt;.do_handle_request_default&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;InvalidZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="nf"&gt;.clone&lt;/span&gt;&lt;span class="p"&gt;())),&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What you can see here is that I'm making sure that we are serving a query (it wouldn't make sense for us to respond to anything else). I have separate handlers for the different zones (subdomains) that I want to service, and I just try to find a match. For example, a lookup for &lt;code&gt;myip.dnsfun.dev&lt;/code&gt; would match the &lt;code&gt;myip_zone&lt;/code&gt;, so that would call the &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L60"&gt;do_handle_request_myip&lt;/a&gt; handler. A lookup for &lt;code&gt;unknown.dnsfun.dev&lt;/code&gt; would match the &lt;code&gt;root_zone&lt;/code&gt;, so it would call the &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L120"&gt;do_handle_request_default&lt;/a&gt; handler. If we get a request for &lt;code&gt;google.com&lt;/code&gt;, which doesn't even match the root zone (&lt;code&gt;dnsfun.dev&lt;/code&gt;), when we don't even issue a response at all.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Handle requests for myip.{domain}.&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_handle_request_myip&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeqCst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MessageResponseBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_message_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;response_from_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.set_authoritative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;match&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.src&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.ip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;V4&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;RData&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;A&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipv4&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
            &lt;span class="nn"&gt;IpAddr&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;V6&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipv6&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nn"&gt;RData&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;AAAA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ipv6&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_rdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="nf"&gt;.send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L60"&gt;do_handle_response_myip&lt;/a&gt; handler, it shouldn't be too complicated: we &lt;a href="https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU64.html#method.fetch_add"&gt;increment the counter&lt;/a&gt;, then we build a response, and we use the &lt;a href="https://docs.rs/trust-dns-server/0.22.0/trust_dns_server/server/struct.Request.html#method.src"&gt;source IP of the request&lt;/a&gt; to determine what to respond with.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Handle requests for counter.{domain}.&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_handle_request_counter&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;counter&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeqCst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MessageResponseBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_message_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;response_from_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.set_authoritative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RData&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;counter&lt;/span&gt;&lt;span class="nf"&gt;.to_string&lt;/span&gt;&lt;span class="p"&gt;()]));&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_rdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="nf"&gt;.send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L79"&gt;do_handle_request_counter&lt;/a&gt; is similarly simple: we &lt;a href="https://doc.rust-lang.org/std/sync/atomic/struct.AtomicU64.html#method.fetch_add"&gt;increment the counter&lt;/a&gt;, which returns the old value of it. Then we take that value, convert it to text and create a response with a text record.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="k"&gt;impl&lt;/span&gt; &lt;span class="n"&gt;Handler&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="cd"&gt;/// Handle requests for *.hello.{domain}.&lt;/span&gt;
    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="k"&gt;fn&lt;/span&gt; &lt;span class="n"&gt;do_handle_request_hello&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ResponseHandler&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Request&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;R&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;Result&lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ResponseInfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.counter&lt;/span&gt;&lt;span class="nf"&gt;.fetch_add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nn"&gt;Ordering&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;SeqCst&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;MessageResponseBuilder&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_message_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="k"&gt;mut&lt;/span&gt; &lt;span class="n"&gt;header&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;Header&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;response_from_request&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.header&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;
        &lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="nf"&gt;.set_authoritative&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.borrow&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;zone_parts&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="nf"&gt;.num_labels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="k"&gt;self&lt;/span&gt;&lt;span class="py"&gt;.hello_zone&lt;/span&gt;&lt;span class="nf"&gt;.num_labels&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;as&lt;/span&gt; &lt;span class="nb"&gt;usize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;name&lt;/span&gt;
            &lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.enumerate&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
            &lt;span class="nf"&gt;.filter&lt;/span&gt;&lt;span class="p"&gt;(|(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;zone_parts&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="nf"&gt;.fold&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"hello,"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)|&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;" "&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="nn"&gt;String&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_utf8_lossy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nn"&gt;RData&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nn"&gt;TXT&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;new&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;]));&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nd"&gt;vec!&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nn"&gt;Record&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nf"&gt;from_rdata&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;request&lt;/span&gt;&lt;span class="nf"&gt;.query&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.name&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="nf"&gt;.into&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;60&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;rdata&lt;/span&gt;&lt;span class="p"&gt;)];&lt;/span&gt;
        &lt;span class="k"&gt;let&lt;/span&gt; &lt;span class="n"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="nf"&gt;.build&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;header&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;records&lt;/span&gt;&lt;span class="nf"&gt;.iter&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[],&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="p"&gt;[]);&lt;/span&gt;
        &lt;span class="nf"&gt;Ok&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;responder&lt;/span&gt;&lt;span class="nf"&gt;.send_response&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;response&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="k"&gt;.await&lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, the &lt;a href="https://github.com/xfbs/dnsfun/blob/5e8a7201b80db6e146d56693788eb8a295f406ec/src/handler.rs#L95"&gt;do_handle_request_hello&lt;/a&gt; is a bit complicated, because we have to extract the name part from the query. For example, when you make a query for &lt;code&gt;patrick.hello.dnsfun.dev&lt;/code&gt;, we return &lt;code&gt;hello, patrick&lt;/code&gt;. So part of this complexity here is taking the query, splitting it into parts like &lt;code&gt;["patrick", "hello", "dnsfun", "dev"]&lt;/code&gt;, and then chopping the last parts off, leaving &lt;code&gt;["patrick"]&lt;/code&gt;, and then creating a string from that. That is what the iterators are doing here.&lt;/p&gt;

&lt;p&gt;To get some nice error messages, we also create our own error type. This is something that &lt;a href="https://docs.rs/thiserror"&gt;thiserror&lt;/a&gt; makes very easy, we can just create an enum and give it some information on how the errors should be displayed, and it takes care of the rest.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight rust"&gt;&lt;code&gt;&lt;span class="nd"&gt;#[derive(thiserror::Error,&lt;/span&gt; &lt;span class="nd"&gt;Debug)]&lt;/span&gt;
&lt;span class="k"&gt;pub&lt;/span&gt; &lt;span class="k"&gt;enum&lt;/span&gt; &lt;span class="n"&gt;Error&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nd"&gt;#[error(&lt;/span&gt;&lt;span class="s"&gt;"Invalid OpCode {0:}"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="nf"&gt;InvalidOpCode&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;OpCode&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nd"&gt;#[error(&lt;/span&gt;&lt;span class="s"&gt;"Invalid MessageType {0:}"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="nf"&gt;InvalidMessageType&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;MessageType&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nd"&gt;#[error(&lt;/span&gt;&lt;span class="s"&gt;"Invalid Zone {0:}"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="nf"&gt;InvalidZone&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;LowerName&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="nd"&gt;#[error(&lt;/span&gt;&lt;span class="s"&gt;"IO error: {0:}"&lt;/span&gt;&lt;span class="nd"&gt;)]&lt;/span&gt;
    &lt;span class="nf"&gt;Io&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nd"&gt;#[from]&lt;/span&gt; &lt;span class="nn"&gt;std&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="nn"&gt;io&lt;/span&gt;&lt;span class="p"&gt;::&lt;/span&gt;&lt;span class="n"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Trying out the DNS server
&lt;/h2&gt;

&lt;p&gt;Again, we can run the server locally using &lt;code&gt;cargo run&lt;/code&gt;. Running queries against it with &lt;code&gt;dig&lt;/code&gt; shows that all of the features are working as expected:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig +short @127.0.0.1 -p 1053 patrick.hello.dnsfun.dev
"hello, patrick"
$ dig +short @127.0.0.1 -p 1053 elon.musk.hello.dnsfun.dev
"hello, elon musk"
$ dig +short @127.0.0.1 -p 1053 counter.dnsfun.dev
"3"
$ dig +short @127.0.0.1 -p 1053 counter.dnsfun.dev
"4"
$ dig +short @127.0.0.1 -p 1053 myip.dnsfun.dev
127.0.0.1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Containerizing the DNS Server
&lt;/h2&gt;

&lt;p&gt;Now that we have built it, we need some way of deploying it. Since we are using Rust, we can simply build and deploy the binary, because it has no dependencies. But in the real world, that is not always the case. Maybe it needs some data at runtime, or it needs some specific libraries. Containerizing makes it possible to bundle it, along with all of the runtime data it needs, and deploy it anywhere.&lt;/p&gt;

&lt;p&gt;We are using &lt;a href="https://en.wikipedia.org/wiki/Docker_(software)"&gt;Docker&lt;/a&gt; to do this, so all we need to do is write a small &lt;a href="https://docs.docker.com/engine/reference/builder/"&gt;Dockerfile&lt;/a&gt; to drop into the repository that tells Docker how to build the container for this service. The diff for this step is &lt;a href="https://github.com/xfbs/dnsfun/commit/6554d2fa3bde699b81b16251ab550d7935779750"&gt;here&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;rust&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;builder&lt;/span&gt;

&lt;span class="c"&gt;# copy code files&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; Cargo.toml Cargo.lock /code/&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; /src/ /code/src/&lt;/span&gt;

&lt;span class="c"&gt;# build code&lt;/span&gt;
&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /code&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;cargo build &lt;span class="nt"&gt;--release&lt;/span&gt;

&lt;span class="c"&gt;# runtime container&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;debian:11&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;runtime&lt;/span&gt;

&lt;span class="c"&gt;# set default logging, can be overridden&lt;/span&gt;
&lt;span class="k"&gt;ENV&lt;/span&gt;&lt;span class="s"&gt; RUST_LOG=info&lt;/span&gt;

&lt;span class="c"&gt;# copy binary&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=builder /code/target/release/dnsfun /usr/local/bin/dnsfun&lt;/span&gt;

&lt;span class="c"&gt;# set entrypoint&lt;/span&gt;
&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/usr/local/bin/dnsfun"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This Dockerfile works in two stages: in the first stage, we use a &lt;code&gt;rust&lt;/code&gt; image to build the service, resulting in a binary. In the next stage, we copy this binary into an empty &lt;code&gt;debian&lt;/code&gt; container. Just for fun, we also add this to our &lt;code&gt;Cargo.toml&lt;/code&gt; to make sure that the resulting binary is small:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[profile.release]
opt-level = "z"
lto = "thin"
debug = false
strip = true
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;What this does is tell the compiler to &lt;a href="https://github.com/johnthagen/min-sized-rust"&gt;optimize for small file size, perform some thin link-time optimisation, and strip debug symbols from the resulting binary&lt;/a&gt;. This results in a 2MB binary, there is certainly still a lot of room for making it smaller but this is good enough. &lt;/p&gt;

&lt;h2&gt;
  
  
  Automating the build
&lt;/h2&gt;

&lt;p&gt;Normally, I prefer to use &lt;a href="https://gitlab.com"&gt;GitLab&lt;/a&gt; and their CI system, but for this project we are using GitHub. What we want to achieve is that this project be compiled, the Docker container created and pushed to the &lt;a href="https://hub.docker.com/"&gt;Docker Hub&lt;/a&gt; automatically on every push. We can do this with &lt;a href="https://github.com/features/actions"&gt;GitHub Actions&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;We don't even have to come up with something on our own. We can just copy the sample configuration from the &lt;a href="https://github.com/actions-rs/meta/blob/master/recipes/quickstart.md"&gt;actions-rs&lt;/a&gt; project to build and test the Rust code automatically, and the &lt;a href="https://github.com/marketplace/actions/build-and-push-docker-images"&gt;sample config for Docker&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The configuration files need to be placed inside the &lt;code&gt;.github/workflows/&lt;/code&gt; folder. &lt;a href="https://github.com/xfbs/dnsfun/commit/44aa41547a6bbfd22f319f46728e51da2dc3866a"&gt;You can see here what they look like&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Deploying DNS-Fun
&lt;/h2&gt;

&lt;p&gt;I went ahead and purchased the domain &lt;code&gt;dnsfun.dev&lt;/code&gt; from &lt;a href="https://inwx.de"&gt;my registrar&lt;/a&gt; for 19.99€, and I purchased a VPS from my &lt;a href="https://hetzner.com"&gt;cloud provider&lt;/a&gt; for about 4.50€ per month. I then logged in to that VPS and ran something like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ apt update
$ apt install docker.io apparmor-utils
$ docker run --name dnsfun -p 53:1053/udp xfbs/dnsfun --udp 0.0.0.0:1053
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I had to do a few steps to get this VPS to be it's own name server -- I won't show you how it's done because it's different for every provider. But it's not too hard, you have to set some glue records and then update the nameserver settings. Piece of cake.&lt;/p&gt;

&lt;p&gt;Now, you can make requests to it! You can either make requests through your normal DNS resolver, which means that the responses are cached:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig +short counter.dnsfun.dev TXT
"2140997"
$ dig +short mike.hello.dnsfun.dev TXT
"hello, mike"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or, you can make request directly to it. The IP address of the server is &lt;code&gt;159.69.35.198&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;$ dig +short @159.69.35.198 counter.dnsfun.dev TXT
"2141001"
$ dig +short @159.69.35.198 myip.dnsfun.dev
123.23.45.67
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I'm going to leave this thing running. Feel free to play around with it as you please. You can even try to break it, too. If you discover any issues, please open up an issue on &lt;a href="https://github.com/xfbs/dnsfun"&gt;GitHub&lt;/a&gt;. If you have any fun ideas on what to implement, create a pull request. I will accept all of them and deploy them.&lt;/p&gt;

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

&lt;p&gt;Rust is certainly not the easiest language, but I like the expressiveness of it. The trait system makes building composable software easy. The macro system, although it feels a little bit like &lt;em&gt;black magic&lt;/em&gt;, feels like fresh air compared to some other languages and helps keep code clean. I'm very impressed with the ecosystem that Rust has to offer.&lt;/p&gt;

&lt;p&gt;I hope you enjoyed reading this blog post, it did turn out to be quite long. I wanted to walk you through the entire process of building and deploying this, without skipping over any parts.&lt;/p&gt;

</description>
      <category>rust</category>
      <category>dns</category>
      <category>fun</category>
      <category>server</category>
    </item>
    <item>
      <title>Passgen: A password generator that uses a regex-like syntax to create secure passwords of any shape.</title>
      <dc:creator>Patrick Elsen</dc:creator>
      <pubDate>Sun, 14 Aug 2022 13:54:29 +0000</pubDate>
      <link>https://dev.to/xfbs/passgen-a-password-generator-that-uses-a-regex-like-syntax-to-create-secure-passwords-of-any-shape-2b7f</link>
      <guid>https://dev.to/xfbs/passgen-a-password-generator-that-uses-a-regex-like-syntax-to-create-secure-passwords-of-any-shape-2b7f</guid>
      <description>&lt;p&gt;I have a bit of a love-hate relationship with passwords. On the one hand, they are necessary for authenticating with services, and for decrypting drives. On the other hand, losing them means losing data or access to accounts. Choosing simpler passwords or reusing them across accounts makes dealing with them easier, but compromises their security. &lt;/p&gt;

&lt;p&gt;Ideally, passwords should be as long as possible&lt;sup id="fnref1"&gt;1&lt;/sup&gt;. While previously, the advice was to use password policies (such as enforcing the use of special characters), current best practice is to avoid that&lt;sup id="fnref2"&gt;2&lt;/sup&gt;, and instead to encourage long passwords. Popular computer comic XKCD &lt;a href="https://xkcd.com/936/" rel="noopener noreferrer"&gt;#936&lt;/a&gt; notes that long word-based passwords have more strength and memorability than special-character-based passwords:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fpassword_strength.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fimgs.xkcd.com%2Fcomics%2Fpassword_strength.png" alt="XKCD 936"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Based on this, I wanted to set out to build a tool that could help with generating random, strong passwords with different shapes. I wanted it to be very flexible, so that you can easily create passwords with different shapes (like, &lt;em&gt;16 alphanumeric characters&lt;/em&gt;, or &lt;em&gt;4 english words&lt;/em&gt;).&lt;/p&gt;

&lt;h2&gt;
  
  
  Regular Expressions
&lt;/h2&gt;

&lt;p&gt;I'm also a very happy used of regular expressions. This is a language that is often used for filtering or searching text-based content. For example, the regular expression &lt;code&gt;[a-z]{8}&lt;/code&gt; will match on any input that consists of exactly eight lowercase latin characters. If you are not familiar with regular expressions, here is a table that showcases their syntax:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;th&gt;Regex&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;The literal string &lt;code&gt;abc&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;abc&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Either an &lt;code&gt;a&lt;/code&gt;, a &lt;code&gt;b&lt;/code&gt;, or a &lt;code&gt;c&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[abc]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Any lowercase latin character&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[a-z]&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 lowercase latin characters&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[a-z]{16}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Normally, regular expressions are used in code to validate input. For example, you might use a regular expression like &lt;code&gt;[a-z0-9.]{3,16}@yourcompany.com&lt;/code&gt; to validate if something is a valid company email address.&lt;/p&gt;

&lt;p&gt;What if I could build a tool that you can give a regular expression, and it evaluates it in reverse, spitting out a string that matches it rather than determining if a given string matches?&lt;/p&gt;

&lt;p&gt;Out of that idea, &lt;a href="https://passgen.it" rel="noopener noreferrer"&gt;&lt;code&gt;passgen&lt;/code&gt;&lt;/a&gt; was born. It started out as a small single-file C project, and evolved into something I consider actually useful. It supports a small subset of the regular expression syntax and will produce a random string matching that. For example:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# generate a password with eight lower-case latin characters
$ passgen "[a-z]{8}"
nsaaemni
# generate a password with twelve alphanumeric latin characters
$ passgen "[a-zA-Z0-9]{12}"
Lp7FBOldLhJC


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;Passgen is fully unicode-aware, meaning that you can generate passwords for other languages, too. Here's some examples of that in action:&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# password with german characters
$ passgen "[a-zßäüöA-ZÄÜÖ0-9]{8}"
6Mu6cüYI
# password with sixteen japanese characters
$ passgen "[\u{3040}-\u{309F}]{16}"
しがぢゐめまゔょぎっきす゚だぃぷ


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Wordlists
&lt;/h2&gt;

&lt;p&gt;One of the reasons I built Passgen was because I wanted to create more memorable passwords for myself. Using completely random letters makes for passwords that are short, but not memorable, as the XKCD earlier points out. So passgen has the ability to read wordlists and pick random words from these. &lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Random word from wordlist&lt;/td&gt;
&lt;td&gt;&lt;code&gt;\w{english}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Six random word from wordlist, separated by a hyphen&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(\w{english}-){5}\w{english}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Six random word from wordlist, separated by a hyphen, followed by a random number&lt;/td&gt;
&lt;td&gt;&lt;code&gt;(\w{english}-){5}\w{english}[0-9]{1,2}&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For example, if you are on Debian or Ubuntu, and you have the &lt;code&gt;wamerican&lt;/code&gt; package installed, you will have a wordlist available at &lt;code&gt;/usr/share/dict/american-english&lt;/code&gt;. If you are on another platform, there are likely similar preinstalled wordlists you can use. Using the &lt;code&gt;--wordlist&lt;/code&gt; command-line flag lets you load this wordlist and then reference it in the pattern.&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# pick 6 random words
$ passgen --wordlist english:/usr/share/dict/words "(\w{english}-){5}\w{english}"
vichyssoise-outstretching-requisite-weekended-homogenizes-calypsos
# pick 6 random words, and a one or two digit number
$ passgen --wordlist english:/usr/share/dict/words "(\w{english}-){5}\w{english}[0-9]{1,2}"
Karamazov-tasselling-pianos-shirr-devoutly-bullrings0


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Markov Chain
&lt;/h2&gt;

&lt;p&gt;While I think it is a good idea to use random words from a wordlist, I experimented with ways to come up with passwords that are similarly memorable (because they are pronounceable), but not neccessarily straight from a wordlist.&lt;/p&gt;

&lt;p&gt;The idea here is using a &lt;a href="https://en.wikipedia.org/wiki/Markov_chain" rel="noopener noreferrer"&gt;Markov Chain&lt;/a&gt; to "learn" which letters frequently occur together from a dictionary file, and then generating new, random words from that. The outcome is words that are pronounceable, but have ideally more entropy, and thus are harder to crack.&lt;/p&gt;

&lt;p&gt;To use this feature, use &lt;code&gt;\m{wordlist}&lt;/code&gt; rather than &lt;code&gt;\w{wordlist}&lt;/code&gt; in the pattern, it's really as simple as that!&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# generate five words from english markov chain
$ passgen --wordlist english:/usr/share/dict/words "(\m{english}-){4}\m{english}"
dam-bloodling-tempouthed-distnuminest-muchee
# generate four words from english markov chain and a number
$ passgen --wordlist english:/usr/share/dict/words "(\m{english}-){3}\m{english}[0-9]{1,2}"
lariticitude's-lieu's-gadorayons-flers44


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Complexity
&lt;/h2&gt;

&lt;p&gt;Anytime passgen has a choice between multiple options, it knows how many options there are and it can thus keep track of how "random" your password is. This means that it can tell you how many &lt;em&gt;bits of randomness&lt;/em&gt; your password contains, which can tell you something about how difficult it would be for an attacker to crack your password, if the attacker knew the pattern that you used to generate it. For example, if your password has 80 bits of entropy, it would take on average 

&lt;span class="katex-element"&gt;
  &lt;span class="katex"&gt;&lt;span class="katex-mathml"&gt;280=12089258196146291747061762^{80}=1208925819614629174706176&lt;/span&gt;&lt;span class="katex-html"&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;&lt;span class="mord"&gt;2&lt;/span&gt;&lt;span class="msupsub"&gt;&lt;span class="vlist-t"&gt;&lt;span class="vlist-r"&gt;&lt;span class="vlist"&gt;&lt;span&gt;&lt;span class="pstrut"&gt;&lt;/span&gt;&lt;span class="sizing reset-size6 size3 mtight"&gt;&lt;span class="mord mtight"&gt;&lt;span class="mord mtight"&gt;80&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;span class="mrel"&gt;=&lt;/span&gt;&lt;span class="mspace"&gt;&lt;/span&gt;&lt;/span&gt;&lt;span class="base"&gt;&lt;span class="strut"&gt;&lt;/span&gt;&lt;span class="mord"&gt;1208925819614629174706176&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;
&lt;/span&gt;
 attempts to guess it.&lt;/p&gt;

&lt;p&gt;Use the &lt;code&gt;--complexity&lt;/code&gt; flag to tell passgen to output it's estimate of the complexity. Here's some examples:&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# eight lowercase alphabetic characters
$ passgen --complexity "[a-z]{8}"
entropy: 37.603518 bits
qhziaohr
# twelve alphanumeric characters
$ passgen --complexity "[a-zA-Z0-9]{12}"
entropy: 71.450356 bits
IoSNTUNU3M1Q
# six random dictionary words
$ passgen --complexity --wordlist english:/usr/share/dict/words "(\w{english}-){5}\w{english}"
entropy: 100.025099 bits
smirked-Ila-ounces-circumstance's-bedpan-process
# six random markov chain words
$ passgen --complexity --wordlist english:/usr/share/dict/words "(\m{english}-){5}\m{english}"
entropy: 125.801760 bits
confabriquing-mas-Onei-scrite-elaw-inast


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;It is important to keep in mind that this feature is not perfect. If you give passgen a pattern like &lt;code&gt;(a|a){5}&lt;/code&gt;, which technically has zero bits of entropy (it always produces &lt;code&gt;aaaaa&lt;/code&gt;), passgen still calculates a nonzero complexity because passgen makes choices (between the first &lt;code&gt;a&lt;/code&gt; and the second &lt;code&gt;a&lt;/code&gt;). &lt;/p&gt;

&lt;h2&gt;
  
  
  Randomness
&lt;/h2&gt;

&lt;p&gt;Passgen will preferentially use the Kernel's secure random number generator as a source of randomness, which is &lt;code&gt;getrandom()&lt;/code&gt; on Linux and &lt;code&gt;arc4random_buf()&lt;/code&gt; on macOS. It falls back to using &lt;code&gt;/dev/urandom&lt;/code&gt;. However, the source of random data is configurable, it can also use a seeded pseudorandom number generator, but at this time only the insecure &lt;code&gt;xorshift&lt;/code&gt; algorithm is implemented for that.&lt;/p&gt;

&lt;h2&gt;
  
  
  Trivia
&lt;/h2&gt;

&lt;p&gt;Passgen uses libseccomp&lt;sup id="fnref3"&gt;3&lt;/sup&gt; on amd64 platforms to sandbox itself, restricting it to only a small amount of allowed syscalls.&lt;/p&gt;

&lt;p&gt;It can also output as &lt;code&gt;JSON&lt;/code&gt; by passing the &lt;code&gt;--json&lt;/code&gt; option.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;If you want to try it out, the source code is available &lt;a href="https://gitlab.com/xfbs/passgen" rel="noopener noreferrer"&gt;here&lt;/a&gt;, and the &lt;a href="https://passgen.it/releases/" rel="noopener noreferrer"&gt;releases page&lt;/a&gt; has signed releases for a bunch of different architectures and platforms. Please be so kind as to file an issue if something does not work, as I don't have a way of testing all of the builds currently.&lt;/p&gt;

&lt;p&gt;If you are on Debian or Ubuntu, the &lt;code&gt;.deb&lt;/code&gt; releases will be useful for you, because they let you install (and remove) &lt;code&gt;passgen&lt;/code&gt; with APT easily.&lt;/p&gt;

&lt;h2&gt;
  
  
  Summary
&lt;/h2&gt;

&lt;p&gt;The website has an overview of the syntax that is available to use, but here is a quick summary.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Pattern&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Generate the literal string &lt;code&gt;abc&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;passgen "abc"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pick a character from &lt;code&gt;a&lt;/code&gt;, &lt;code&gt;b&lt;/code&gt;, &lt;code&gt;c&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;passgen "[abc]"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pick a character from the range &lt;code&gt;a-z&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;passgen "[a-z]"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Repeat &lt;code&gt;a&lt;/code&gt; four times&lt;/td&gt;
&lt;td&gt;&lt;code&gt;passgen "a{4}"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pick four lowercase characters&lt;/td&gt;
&lt;td&gt;&lt;code&gt;passgen "[a-z]{4}"&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;To generate passwords, you have a number of constructs available to use:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Verbatim characters. The pattern &lt;code&gt;abc&lt;/code&gt; generates the "password" &lt;code&gt;abc&lt;/code&gt;. They are simply passed through.&lt;/li&gt;
&lt;li&gt;Characters sets, enclosed in brackets. You can either list all allowed characters or use ranges of characters, which are inclusive. Examples: &lt;code&gt;[abc]&lt;/code&gt;, &lt;code&gt;[a-zA-Z0-9]&lt;/code&gt;, &lt;code&gt;[0123456789abcdef]&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Groups, enclosed in paretheses. Groups let you list one or more possible patterns. Examples: &lt;code&gt;(word)&lt;/code&gt; generates &lt;em&gt;word&lt;/em&gt;, &lt;code&gt;(this|that)&lt;/code&gt; generates &lt;em&gt;this&lt;/em&gt; or &lt;em&gt;that&lt;/em&gt;, &lt;code&gt;([a-z]|[0-9])&lt;/code&gt; generates a lowercase latin character (&lt;code&gt;[a-z]&lt;/code&gt;) or a number (&lt;code&gt;[0-9]&lt;/code&gt;).&lt;/li&gt;
&lt;li&gt;Repeat. Using braces lets you repeat whatever was before. You can either specify a fixed number or a lower and an upper bound, separated by a comma. Examples: &lt;code&gt;[abc]{3}&lt;/code&gt;, &lt;code&gt;[a-z]{9,12}&lt;/code&gt;, &lt;code&gt;(this|that){2}&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If this syntax is too complicated for you, the passgen binary also comes with some pattern presets, that you can use with the &lt;code&gt;-p&lt;/code&gt; flag. These are named after the software that generates passwords matching these patterns.&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

# generated by older versions of safari
$ passgen -p apple1
asG-mIQ-7jz-LAT
# generated by current safari
$ passgen -p apple2
lHODYM-MgdmfG-llo5kD
# generated by firefox
$ passgen -p firefox
iBpDBlTg8bX051H


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
  
  
  Development
&lt;/h2&gt;

&lt;p&gt;If you are a real nerd, you may want to compile it for yourself. You need some dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CMake&lt;/li&gt;
&lt;li&gt;C compiler (gcc or clang)&lt;/li&gt;
&lt;li&gt;Git&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;With those dependencies, you should be able to build it by cloning the repository, fetching the submodules (this is needed for libutf8proc&lt;sup id="fnref4"&gt;4&lt;/sup&gt;).&lt;/p&gt;
&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

git clone https://gitlab.com/xfbs/passgen
git submodule update --init
mkdir passgen/build
cd passgen/build
cmake ..
make -j8


&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;If you want to understand how pieces of it work, there is also some &lt;a href="https://passgen.it/docs" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; available that is built off the master branch.&lt;/p&gt;

&lt;h2&gt;
  
  
  Tests
&lt;/h2&gt;

&lt;p&gt;Passgen has a number of unit tests built-in, you can run these with &lt;code&gt;make test&lt;/code&gt;. You can also run these tests under valgrind if you have it installed, this will let you make sure that there are no memory leaks.&lt;/p&gt;


&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;

&lt;p&gt;$ valgrind ./src/test/passgen-test -v&lt;/p&gt;

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;
&lt;h2&gt;
&lt;br&gt;
  &lt;br&gt;
  &lt;br&gt;
  Support&lt;br&gt;
&lt;/h2&gt;

&lt;p&gt;Your support is appreciated. If you run passgen, and something doesn't work, please let me know. You can file an issue in the &lt;a href="https://gitlab.com/xfbs/passgen" rel="noopener noreferrer"&gt;repository&lt;/a&gt; and I will try to fix it. &lt;/p&gt;

&lt;p&gt;If you enjoy passgen, and you find bugs, have suggestions, or want to help get it into any package repositories, please don't hesitate to reach out to me, I appreciate any help. I hope that it can be useful to other people.&lt;/p&gt;




&lt;ol&gt;

&lt;li id="fn1"&gt;
&lt;p&gt;Minimum length of the passwords should be enforced by the application. Passwords shorter than 8 characters are considered to be weak. &lt;a href="https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html" rel="noopener noreferrer"&gt;https://cheatsheetseries.owasp.org/cheatsheets/Authentication_Cheat_Sheet.html&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn2"&gt;
&lt;p&gt;&lt;a href="https://www.troyhunt.com/passwords-evolved-authentication-guidance-for-the-modern-era/" rel="noopener noreferrer"&gt;https://www.troyhunt.com/passwords-evolved-authentication-guidance-for-the-modern-era/&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn3"&gt;
&lt;p&gt;&lt;a href="https://github.com/seccomp/libseccomp" rel="noopener noreferrer"&gt;https://github.com/seccomp/libseccomp&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;li id="fn4"&gt;
&lt;p&gt;utf8proc, a UTF-8 decoding library. &lt;a href="https://github.com/JuliaStrings/utf8proc" rel="noopener noreferrer"&gt;https://github.com/JuliaStrings/utf8proc&lt;/a&gt; ↩&lt;/p&gt;
&lt;/li&gt;

&lt;/ol&gt;

</description>
      <category>password</category>
      <category>secure</category>
      <category>regex</category>
      <category>security</category>
    </item>
  </channel>
</rss>
