<?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: Ciro S. Costa</title>
    <description>The latest articles on DEV Community by Ciro S. Costa (@cirowrc).</description>
    <link>https://dev.to/cirowrc</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%2F83652%2F3f4f535d-e530-4926-bc24-dd8764e596b6.jpg</url>
      <title>DEV Community: Ciro S. Costa</title>
      <link>https://dev.to/cirowrc</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/cirowrc"/>
    <language>en</language>
    <item>
      <title>kubectl create pizza</title>
      <dc:creator>Ciro S. Costa</dc:creator>
      <pubDate>Fri, 11 Dec 2020 16:04:47 +0000</pubDate>
      <link>https://dev.to/cirowrc/kubectl-create-pizza-4m0o</link>
      <guid>https://dev.to/cirowrc/kubectl-create-pizza-4m0o</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;I recently created a series of articles and videos that goes through the&lt;br&gt;
development of Kubernetes custom resources and controllers (see&lt;br&gt;
&lt;a href="https://gum.co/kubernetes-crds"&gt;gum.co/kubernetes-crds&lt;/a&gt;), but I missed that&lt;br&gt;
nice catchy example that would showcase what custom resources are all about.&lt;/p&gt;

&lt;p&gt;So, why not implement the ultimate missing feature that Kubernetes should have?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cP_1FTB---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/3574444/101922101-b81fe600-3b9b-11eb-95a3-9a5f2a067997.JPG" class="article-body-image-wrapper"&gt;&lt;img width="300px" src="https://res.cloudinary.com/practicaldev/image/fetch/s--cP_1FTB---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/3574444/101922101-b81fe600-3b9b-11eb-95a3-9a5f2a067997.JPG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;em&gt;tl;dr: see &lt;a href="https://github.com/cirocosta/pizza-controller"&gt;https://github.com/cirocosta/pizza-controller&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;
&lt;h2&gt;
  
  
  usage
&lt;/h2&gt;

&lt;p&gt;First, create a secret with the credit card information (&lt;em&gt;yeah, this is fine,&lt;br&gt;
trust me&lt;/em&gt;) to be used during payment:&lt;br&gt;
&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Secret&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;v1&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;credit-card&lt;/span&gt;
&lt;span class="na"&gt;stringData&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;number&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123343132314232&lt;/span&gt;
  &lt;span class="na"&gt;expiration&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;12/02&lt;/span&gt;
  &lt;span class="na"&gt;securityCode&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt;
  &lt;span class="na"&gt;zip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;m5d0l2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;then, create a &lt;code&gt;PizzaCustomer&lt;/code&gt;, the representation of &lt;em&gt;you&lt;/em&gt;, the customer:&lt;br&gt;
&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PizzaCustomer&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ops.tips/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;you&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;firstName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;barack&lt;/span&gt;
  &lt;span class="na"&gt;lastName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;obama&lt;/span&gt;
  &lt;span class="na"&gt;email&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;obama@gov.gov&lt;/span&gt;
  &lt;span class="na"&gt;phone&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;31241323"&lt;/span&gt;
  &lt;span class="na"&gt;streetNumber&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;20"&lt;/span&gt;
  &lt;span class="na"&gt;streetName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;King St&lt;/span&gt;
  &lt;span class="na"&gt;city&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Toronto&lt;/span&gt;
  &lt;span class="na"&gt;state&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ON"&lt;/span&gt;
  &lt;span class="na"&gt;zip&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;m5lz8j&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the &lt;code&gt;PizzaCustomer&lt;/code&gt; object created, we can see what's the closest store available&lt;br&gt;
for it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get pizzacustomer
&lt;span class="go"&gt;
NAME              CLOSEST
you               store-123
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Looking at the PizzaStore object, we can check out its menu:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get pizzastore store-123 &lt;span class="nt"&gt;-o&lt;/span&gt; yaml
&lt;span class="go"&gt;
kind: PizzaStore
metadata:
  name: store-123
spec:
  address: |
    51 Niagara St
    Toronto, ON M5V1C3
  id: "10391"
  phone: 416-364-3939
  products:
    - description: Unique Lymon (lemon-lime) flavor, clear, clean and crisp with no caffeine.
      id: 2LSPRITE
      name: Sprite
      size: 2 Litre
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Knowing what's available to us, we can place the order:&lt;br&gt;
&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;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;PizzaOrder&lt;/span&gt;
&lt;span class="na"&gt;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ops.tips/v1&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;ma-pizza&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;yeahSurePlaceThisOrder&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="no"&gt;true&lt;/span&gt;  &lt;span class="c1"&gt;# otherwise, it'll just calculate the price&lt;/span&gt;
  &lt;span class="na"&gt;storeRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;store-123&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;customerRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;you&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;payment&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="na"&gt;creditCardSecretRef&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;{&lt;/span&gt;&lt;span class="nv"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="nv"&gt;cc&lt;/span&gt;&lt;span class="pi"&gt;}&lt;/span&gt;
  &lt;span class="na"&gt;items&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
    &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;ticker&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;10SCREEN&lt;/span&gt;
      &lt;span class="na"&gt;quantity&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To keep track of what's going on with your pizza, check out the order's status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight console"&gt;&lt;code&gt;&lt;span class="gp"&gt;$&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;kubectl get pizzaorder ma-pizza
&lt;span class="go"&gt;
NAME    PRICE      ID                     CONDITION     AGE
order   9.030000   Wlz6HcE6BPlfQNlxDAXa   OrderPlaced   68m
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;and, there we go!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4owNiEbx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/3574444/101922114-bb1ad680-3b9b-11eb-8850-5fca08598d2d.JPG" class="article-body-image-wrapper"&gt;&lt;img width="300px" src="https://res.cloudinary.com/practicaldev/image/fetch/s--4owNiEbx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://user-images.githubusercontent.com/3574444/101922114-bb1ad680-3b9b-11eb-8850-5fca08598d2d.JPG"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  wait, but why?
&lt;/h2&gt;

&lt;p&gt;no no, wait, &lt;strong&gt;why not&lt;/strong&gt;?&lt;/p&gt;

&lt;p&gt;see, with CI/CD being part of Kubernetes through projects like Argo and Tekton,&lt;br&gt;
where you declare what your pipeline/workflow will be in terms of Kubernetes&lt;br&gt;
resources, we're now able to get that nice pizza for the team after a&lt;br&gt;
successfull release.&lt;br&gt;
&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;apiVersion&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;argoproj.io/v1alpha1&lt;/span&gt;
&lt;span class="na"&gt;kind&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Workflow&lt;/span&gt;
&lt;span class="na"&gt;metadata&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;generateName&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release-&lt;/span&gt;
&lt;span class="na"&gt;spec&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="na"&gt;entrypoint&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;pi-tmpl&lt;/span&gt;
  &lt;span class="na"&gt;templates&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;main&lt;/span&gt;
    &lt;span class="na"&gt;steps&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;unit-tests&lt;/span&gt;
          &lt;span class="na"&gt;template&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="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integration-tests&lt;/span&gt;
          &lt;span class="na"&gt;template&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;arguments&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
            &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
              &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;type&lt;/span&gt;
                &lt;span class="na"&gt;value&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;integration&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;release&lt;/span&gt;
      &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;get-that-pizza&lt;/span&gt;
          &lt;span class="na"&gt;template&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;order-pizza&lt;/span&gt;

  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="na"&gt;name&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;order-pizza&lt;/span&gt;
    &lt;span class="na"&gt;resource&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
      &lt;span class="na"&gt;action&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;create&lt;/span&gt;      
      &lt;span class="na"&gt;manifest&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="pi"&gt;|&lt;/span&gt;
        &lt;span class="s"&gt;kind: PizzaOrder&lt;/span&gt;
        &lt;span class="s"&gt;apiVersion: ops.tips/v1&lt;/span&gt;
        &lt;span class="s"&gt;metadata:&lt;/span&gt;
          &lt;span class="s"&gt;name: ma-pizza&lt;/span&gt;
        &lt;span class="s"&gt;spec:&lt;/span&gt;
          &lt;span class="s"&gt;yeahSurePlaceThisOrder: true&lt;/span&gt;
          &lt;span class="s"&gt;storeRef: {name: store-123}&lt;/span&gt;
          &lt;span class="s"&gt;customerRef: {name: you}&lt;/span&gt;
          &lt;span class="s"&gt;payment:&lt;/span&gt;
            &lt;span class="s"&gt;creditCardSecretRef: {name: cc}&lt;/span&gt;
          &lt;span class="s"&gt;items:&lt;/span&gt;
            &lt;span class="s"&gt;- ticker: 10SCREEN&lt;/span&gt;
              &lt;span class="s"&gt;quantity: 2&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;i don't know about you, but that sounds quite right to me &lt;code&gt;¯\_(ツ)_/¯&lt;/code&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  installation
&lt;/h2&gt;

&lt;p&gt;being a legit Kubernetes custom resource, you install it just like you would&lt;br&gt;
install Tekton, kpack, or anything like that: you submit a manifest that&lt;br&gt;
contains the &lt;code&gt;CustomResourceDefinition&lt;/code&gt; objects to Kubernetes, a &lt;code&gt;Deployment&lt;/code&gt;&lt;br&gt;
that materializes the controller as a container in a pod, and then ... that's&lt;br&gt;
it!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/cirocosta/pizza-controller
&lt;span class="nb"&gt;cd &lt;/span&gt;pizza-controller

kapp deploy &lt;span class="nt"&gt;-a&lt;/span&gt; pizza-controller &lt;span class="nt"&gt;-f&lt;/span&gt; ./config/release.yaml


&lt;span class="c"&gt;# OR .. plain old kubectl&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; ./config/release.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  but, that's dumb
&lt;/h2&gt;

&lt;p&gt;i disagree&lt;/p&gt;

&lt;p&gt;I think it's a pretty cool example of the concepts behind extending&lt;br&gt;
kubernetes via custom resources, and something that might bring you some&lt;br&gt;
thoughts of ways in which you could bring the&lt;br&gt;
declarative nature of Kubernetes objects plus the level-triggered approach to&lt;br&gt;
controllers to bring to Kubernetes the ability to request external resources.&lt;/p&gt;

&lt;p&gt;for instance, projects like &lt;a href="https://crossplane.io/"&gt;crossplane&lt;/a&gt; give you pretty&lt;br&gt;
much that, except that instead of ordering a pizza, you're ordering ... a&lt;br&gt;
database (or things like that).&lt;/p&gt;

&lt;h2&gt;
  
  
  what's next?
&lt;/h2&gt;

&lt;p&gt;are you &lt;em&gt;really&lt;/em&gt; into ordering pizza using &lt;code&gt;kubectl&lt;/code&gt;?&lt;/p&gt;

&lt;p&gt;like, really? are you sure?&lt;/p&gt;

&lt;p&gt;here's what's missing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;well, any .. tests 🐴&lt;/li&gt;
&lt;li&gt;order tracking (it's &lt;code&gt;xml&lt;/code&gt;-based - SOAP stuff)&lt;/li&gt;
&lt;li&gt;being more flexible with non-canadian folks (it's currently hardcoded for
Canada, but could easily be changed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;at the moment I got my pizza .. development finished 😅 maybe you'll&lt;br&gt;
carry it forward? head to &lt;a href="https://github.com/cirocosta/pizza-controller"&gt;https://github.com/cirocosta/pizza-controller&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  want to know more?
&lt;/h2&gt;

&lt;p&gt;check out &lt;a href="https://gum.co/kubernetes-crds"&gt;https://gum.co/kubernetes-crds&lt;/a&gt;&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>go</category>
    </item>
    <item>
      <title>Article recommendation using Hugo</title>
      <dc:creator>Ciro S. Costa</dc:creator>
      <pubDate>Sat, 06 Oct 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/cirowrc/article-recommendation-using-hugo-3974</link>
      <guid>https://dev.to/cirowrc/article-recommendation-using-hugo-3974</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;This month I’ve been interested in increasing the overall time that a user spends navigating there in the blog (&lt;a href="https://ops.tips" rel="noopener noreferrer"&gt;ops.tips&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Being article recommendation something that the blog was missing, I went for it.&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%2Fops.tips%2Fblog%2F-%2Fimages%2Frecommended-articles.svg" 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%2Fops.tips%2Fblog%2F-%2Fimages%2Frecommended-articles.svg" alt="Article recommendation in use"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Check out how you can do it for your static site too!&lt;/p&gt;

&lt;h3&gt;
  
  
  The idea
&lt;/h3&gt;

&lt;p&gt;Given that my content usually is tagged, I thought that one easy way of adding article recommendation would be to simply take the union between the articles tagged with the same tag as the current one and then randomly list them.&lt;/p&gt;

&lt;p&gt;For instance, consider the case of this article: &lt;a href="https://ops.tips/blog/udp-client-and-server-in-go/" rel="noopener noreferrer"&gt;A UDP server and client in Go&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Being the article tagged as &lt;a href="https://ops.tips/tags/linux" rel="noopener noreferrer"&gt;Linux&lt;/a&gt;, &lt;a href="https://ops.tips/tags/networking" rel="noopener noreferrer"&gt;Networking&lt;/a&gt;, and &lt;a href="https://ops.tips/tags/go" rel="noopener noreferrer"&gt;Go&lt;/a&gt;, we can infer that there are three pools of content that might be similar to what’s been there in this article (having some overlap between them).&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%2Fops.tips%2Fblog%2F-%2Fimages%2Frecommendation-overlap.svg" 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%2Fops.tips%2Fblog%2F-%2Fimages%2Frecommendation-overlap.svg" alt="Overlap between bag of articles by selecting articles with tags matching"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Moving forward, we can think that once we addressed the possible articles to recommend, the next step is to give preference to some of them: rank higher those with more overlap in more categories.&lt;/p&gt;

&lt;p&gt;Let’s implement that then.&lt;/p&gt;

&lt;h3&gt;
  
  
  Implementing a Recommended Articles list in Hugo
&lt;/h3&gt;

&lt;p&gt;As a first step, we retrive all the pages that are not the currently page that we are seeing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Assign the current scope (the current page) to&lt;/span&gt;
&lt;span class="c1"&gt;// a variable named `$currentArticle` so that within&lt;/span&gt;
&lt;span class="c1"&gt;// other scopes we are able to still reference the &lt;/span&gt;
&lt;span class="c1"&gt;// current page.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$currentArticle&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

&lt;span class="c1"&gt;// From the list of all pages from the site, only keep&lt;/span&gt;
&lt;span class="c1"&gt;// those whose name is different from the name of the&lt;/span&gt;
&lt;span class="c1"&gt;// current article and whose kind is `page`.&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;// ps.: here we could check something else, like permalink&lt;/span&gt;
&lt;span class="c1"&gt;// or another unique identifier.&lt;/span&gt;
&lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="c1"&gt;// ps.: here you'd probably pick a specific section. To do&lt;/span&gt;
&lt;span class="c1"&gt;// so, perform another `where`.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$articles&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nf"&gt;where&lt;/span&gt; 
        &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;where&lt;/span&gt; &lt;span class="nv"&gt;$&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Site&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Pages&lt;/span&gt; &lt;span class="s"&gt;".Kind"&lt;/span&gt; &lt;span class="s"&gt;"eq"&lt;/span&gt; &lt;span class="s"&gt;"page"&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; 
        &lt;span class="s"&gt;".Title"&lt;/span&gt; &lt;span class="s"&gt;"!="&lt;/span&gt; &lt;span class="nv"&gt;$currentArticle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;note.: the &lt;code&gt;where&lt;/code&gt; above &lt;strong&gt;must&lt;/strong&gt; be inlined. Here I broke it in multiple lines just for achieving better readability.&lt;/p&gt;

&lt;p&gt;Next, we now create two lists:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;one that references all articles with &lt;strong&gt;at least two&lt;/strong&gt; tags that are in the set of tags in the current article; and&lt;/li&gt;
&lt;li&gt;a list that references all articles with &lt;strong&gt;a single&lt;/strong&gt; tag in the set of tags of the current article.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;We can call these two &lt;code&gt;veryRelevantArticles&lt;/code&gt; and &lt;code&gt;relevantArticles&lt;/code&gt; (accordingly):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instantiate each of them with an empty slice.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$relevantArticles&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the variables set, we can now start iterating over our list of all article pages and checking how many intersections they have with the set of tags from our current page:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Iterate over each of the articles from the list &lt;/span&gt;
&lt;span class="c1"&gt;// of article pages&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="nc"&gt;$idx&lt;/span&gt;&lt;span class="o"&gt;,&lt;/span&gt; &lt;span class="nc"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nc"&gt;$articles&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
        &lt;span class="c1"&gt;// Compute the number of tag intersactions.&lt;/span&gt;
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$numberOfIntersections&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nf"&gt;len&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;
                &lt;span class="n"&gt;intersect&lt;/span&gt; &lt;span class="nv"&gt;$article&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;tags&lt;/span&gt; &lt;span class="nv"&gt;$currentArticle&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Params&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Tags&lt;/span&gt;
        &lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

        &lt;span class="c1"&gt;// For those pages with a big number of &lt;/span&gt;
        &lt;span class="c1"&gt;// intersections (&amp;gt;= 2), put in the first&lt;/span&gt;
        &lt;span class="c1"&gt;// slice.&lt;/span&gt;
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ge&lt;/span&gt; &lt;span class="nc"&gt;$numberOfIntersections&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
                &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; 
                        &lt;span class="nc"&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="nc"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
        &lt;span class="c1"&gt;// For the rest (single intersaction), put in the &lt;/span&gt;
        &lt;span class="c1"&gt;// second slice.&lt;/span&gt;
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="nf"&gt;if&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;eq&lt;/span&gt; &lt;span class="nc"&gt;$numberOfIntersections&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
                &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$relevantArticles&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; 
                        &lt;span class="nc"&gt;$relevantArticles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="nc"&gt;$article&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

        &lt;span class="c1"&gt;// note.: I'm ignoring those with 0 intersections.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once we’ve gotten all interesting articles, now we can create an ordered list starting from those with the biggest number of recommendations to those with the lowest, i.e., we can create a list that corresponds to the concatenation of the two variables we created above:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Create an empty slice to hold the final list&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;slice&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

&lt;span class="c1"&gt;// For each very recommended article, append to the&lt;/span&gt;
&lt;span class="c1"&gt;// list.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="nc"&gt;$veryRelevantArticles&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt; 
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt; 
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

&lt;span class="c1"&gt;// For each recommended article, append to the&lt;/span&gt;
&lt;span class="c1"&gt;// list.&lt;/span&gt;
&lt;span class="c1"&gt;// &lt;/span&gt;
&lt;span class="c1"&gt;// This will lead to something like &lt;/span&gt;
&lt;span class="c1"&gt;// [very, very, rec, rec, rec....]&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="nc"&gt;$relevantArticles&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt; 
        &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt; &lt;span class="k"&gt;=&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;append&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt; 
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the list created, now it’s time to show it.&lt;/p&gt;

&lt;h3&gt;
  
  
  Displaying the recommendation list
&lt;/h3&gt;

&lt;p&gt;With a list containing those with the biggest number of intersections first and then the ones that have the less number of intersections, we can move forward with displaying that.&lt;/p&gt;

&lt;p&gt;For this Blog, I took the approach of showing a shuffle of the very first five that are picked from such list.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight scala"&gt;&lt;code&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;

&lt;span class="c1"&gt;// For every article in the set of the first 5&lt;/span&gt;
&lt;span class="c1"&gt;// recommended articles shuffled, show their&lt;/span&gt;
&lt;span class="c1"&gt;// anchor.&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="nf"&gt;range&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;shuffle&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="n"&gt;first&lt;/span&gt; &lt;span class="mi"&gt;5&lt;/span&gt; &lt;span class="nc"&gt;$recommendedArticles&lt;/span&gt;&lt;span class="o"&gt;))&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt; &lt;span class="n"&gt;href&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;"{{ .Permalink }}"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="py"&gt;Title&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;
  &lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;li&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;end&lt;/span&gt; &lt;span class="o"&gt;}}&lt;/span&gt;

&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;ul&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This guarantees that if I have some articles with big intersections with the content of the current article, they get displayed (even though unordered).&lt;/p&gt;

&lt;p&gt;If you have a lot of content, and a lot of tags, you might want to create more categories (not only &lt;code&gt;veryRelevant&lt;/code&gt; and &lt;code&gt;relevant&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;In such case, something more elaborate could be done.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing thoughts
&lt;/h3&gt;

&lt;p&gt;It’s interesting to see how much we can accomplish without “an actual language”.&lt;/p&gt;

&lt;p&gt;Although Hugo gives us some simple primitives, we can build upon that and achieve some pretty satisfactory results.&lt;/p&gt;

&lt;p&gt;What about you? Have you ever achieved something similar doing something different? Please let me know!&lt;/p&gt;

&lt;p&gt;Also, if you have any questions, feel free to drop me a message at &lt;a href="https://twitter.com/cirowrc" rel="noopener noreferrer"&gt;@cirowrc&lt;/a&gt; on Twitter.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>hugo</category>
      <category>writting</category>
      <category>devtips</category>
    </item>
    <item>
      <title>A UDP server and client in Go</title>
      <dc:creator>Ciro S. Costa</dc:creator>
      <pubDate>Sun, 30 Sep 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/cirowrc/a-udp-server-and-client-in-go-3g8n</link>
      <guid>https://dev.to/cirowrc/a-udp-server-and-client-in-go-3g8n</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;While it’s prevalent to see implementations of TCP servers in Golang, it’s not very common to see the same when it comes to UDP.&lt;/p&gt;

&lt;p&gt;Besides the many differences between UDP and TCP, using Go it feels like these are pretty much alike, except for little details that arise from each protocol specifics.&lt;/p&gt;

&lt;p&gt;If you feel like some Golang UDP knowledge would be valuable, make sure you stick to the end.&lt;/p&gt;

&lt;p&gt;As an extra, this article also covers the underlying differences between TCP and UDP when it comes to the syscalls that Golang uses under the hood, as well as some analysis of what the Kernel does when those syscalls get called.&lt;/p&gt;

&lt;p&gt;Stay tuned!&lt;/p&gt;

&lt;h3&gt;
  
  
  Overview
&lt;/h3&gt;

&lt;p&gt;As a goal for the blog post, the final implementation should look like an “echo channel”, where whatever a client writes to the server, the server echoes back.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        .---&amp;gt; HELLO!! --&amp;gt;-.
        |                 |
client -*                 *--&amp;gt; server --.
   ^                                    |
   |                                    |
   *---&amp;lt;----- HELLO!! ---------&amp;lt;--------*

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

&lt;/div&gt;



&lt;p&gt;Being UDP a protocol that doesn’t guarantee reliable delivery, it might be the case that the server receives the message, and it might be the case that the client receives the echo back from the server.&lt;/p&gt;

&lt;p&gt;The flow &lt;strong&gt;might&lt;/strong&gt; complete successfully (or not).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;        .---&amp;gt; HELLO!! --&amp;gt;-.
        |                 |
client -*                 *--&amp;gt; server --.
                                        |
                                        |
            whoops, lost! -----&amp;lt;--------*

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

&lt;/div&gt;



&lt;p&gt;Not being connection-oriented, the client won’t really “establish a connection”, like in TCP; whenever a message arrives at the server, it won’t “write a response back to the connection”, it will only direct a message to the address that wrote to it.&lt;/p&gt;

&lt;p&gt;With that in mind, the flow should look 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;TIME    DESCRIPTION

t0      client and server exist

          client                         server
          10.0.0.1                       10.0.0.2


t1      client sends a message to the server

          client      ------------&amp;gt;      server
          10.0.0.1         msg           10.0.0.2
                       (from:10.0.0.1)
                       (to:  10.0.0.2)


t2      server receives the message, then it takes
        the address of the sender and then prepares
        another message with the same contents and
        then writes it back to the client

          client      &amp;lt;------------      server
          10.0.0.1         msg2          10.0.0.2
                       (from:10.0.0.1)
                       (to:  10.0.0.2)


t3      client receives the message

          client                         server
          10.0.0.1                       10.0.0.2

           thxx!! :D :D


ps.: ports omitted for brevity

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

&lt;/div&gt;



&lt;p&gt;That said, let’s see how that story rolls out in Go.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If you’d like a real deep dive, make sure you consider these books:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://amzn.to/2DEiNOG"&gt;Computer Networking: A top-down approach&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/2zuuMu1"&gt;Unix Network Programming, Volume 1: The Sockets Networking API (3rd Edition)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://amzn.to/2QWyXp9"&gt;The Linux Programming Interface&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The first takes the approach of going from the very high level part of the networking stack (application layer), and then goes down to the very bottom, explaining the details of the protocols in there as it goes through them - if you need an excellent refresher on networking concepts without digging into the implementation details, check this one out!&lt;/p&gt;

&lt;p&gt;The other two are more about Linux and Unix in general - very worthwhile if you’re more focused on the implementation.&lt;/p&gt;

&lt;p&gt;Have a good reading!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Sending UDP packets using Go
&lt;/h3&gt;

&lt;p&gt;Kicking off with the whole implementation at once (full of comments), we can start depicting it, understanding piece by piece, until the point that we can understand each and every interaction that happens behind the scenes.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// client wraps the whole functionality of a UDP client that sends&lt;/span&gt;
&lt;span class="c"&gt;// a message and waits for a response coming back from the server&lt;/span&gt;
&lt;span class="c"&gt;// that it initially targetted.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reader&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Reader&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// Resolve the UDP address so that we can make use of DialUDP&lt;/span&gt;
    &lt;span class="c"&gt;// with an actual IP and port instead of a name (in case a&lt;/span&gt;
    &lt;span class="c"&gt;// hostname is specified).&lt;/span&gt;
    &lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ResolveUDPAddr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Although we're not in a connection-oriented transport,&lt;/span&gt;
    &lt;span class="c"&gt;// the act of `dialing` is analogous to the act of performing&lt;/span&gt;
    &lt;span class="c"&gt;// a `connect(2)` syscall for a socket of type SOCK_DGRAM:&lt;/span&gt;
    &lt;span class="c"&gt;// - it forces the underlying socket to only read and write&lt;/span&gt;
    &lt;span class="c"&gt;// to and from a specific remote address.&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;DialUDP&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;raddr&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// Closes the underlying file descriptor associated with the,&lt;/span&gt;
    &lt;span class="c"&gt;// socket so that it no longer refers to any file.&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// It is possible that this action blocks, although this&lt;/span&gt;
        &lt;span class="c"&gt;// should only occur in very resource-intensive situations:&lt;/span&gt;
        &lt;span class="c"&gt;// - when you've filled up the socket buffer and the OS&lt;/span&gt;
        &lt;span class="c"&gt;// can't dequeue the queue fast enough.&lt;/span&gt;
        &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;io&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Copy&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;reader&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"packet-written: bytes=%d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxBufferSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// Set a deadline for the ReadOperation so that we don't&lt;/span&gt;
        &lt;span class="c"&gt;// wait forever for a server that might not respond on&lt;/span&gt;
        &lt;span class="c"&gt;// a resonable amount of time.&lt;/span&gt;
        &lt;span class="n"&gt;deadline&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;nRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"packet-received: bytes=%d from=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;nRead&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

        &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
    &lt;span class="p"&gt;}()&lt;/span&gt;

    &lt;span class="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cancelled"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;doneChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Having the client code, we can now depict it, exploring each of its nuances.&lt;/p&gt;

&lt;h3&gt;
  
  
  Address resolution
&lt;/h3&gt;

&lt;p&gt;Before we even start creating a socket and carrying about sending the information to the server, the first thing that happens is a name resolution that translates a given name (like, &lt;code&gt;google.com&lt;/code&gt;) into a set of IP addresses (like, &lt;code&gt;8.8.8.8&lt;/code&gt;).&lt;/p&gt;

&lt;p&gt;The way we do that in our code is with the call to &lt;a href="https://golang.org/pkg/net/#ResolveUDPAddr"&gt;net.ResolveUDPAddr&lt;/a&gt;, which in a Unix environment, goes all the way down to performing the DNS resolution via the following stack:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(in a given goroutine ...)
    &amp;gt;&amp;gt; 0 0x00000000004e5dc5 in net.(*Resolver).goLookupIPCNAMEOrder
           at /usr/local/go/src/net/dnsclient_unix.go:553
    &amp;gt;&amp;gt; 1 0x00000000004fbe69 in net.(*Resolver).lookupIP
           at /usr/local/go/src/net/lookup_unix.go:101
        2 0x0000000000514948 in net.(*Resolver).lookupIP-fm
           at /usr/local/go/src/net/lookup.go:207
        3 0x000000000050faca in net.glob..func1
           at /usr/local/go/src/net/hook.go:19
    &amp;gt;&amp;gt; 4 0x000000000051156c in net.(*Resolver).LookupIPAddr.func1
           at /usr/local/go/src/net/lookup.go:221
        5 0x00000000004d4f7c in internal/singleflight.(*Group).doCall
           at /usr/local/go/src/internal/singleflight/singleflight.go:95
        6 0x000000000045d9c1 in runtime.goexit
           at /usr/local/go/src/runtime/asm_amd64.s:1333

(in another goroutine...)
0 0x0000000000431a74 in runtime.gopark
   at /usr/local/go/src/runtime/proc.go:303
1 0x00000000004416dd in runtime.selectgo
   at /usr/local/go/src/runtime/select.go:313
2 0x00000000004fa3f6 in net.(*Resolver).LookupIPAddr &amp;lt;&amp;lt;
   at /usr/local/go/src/net/lookup.go:227
3 0x00000000004f6ae9 in net.(*Resolver).internetAddrList &amp;lt;&amp;lt;
   at /usr/local/go/src/net/ipsock.go:279
4 0x000000000050807d in net.ResolveUDPAddr &amp;lt;&amp;lt;
   at /usr/local/go/src/net/udpsock.go:82
5 0x000000000051e63b in main.main
   at ./resolve.go:14
6 0x0000000000431695 in runtime.main
   at /usr/local/go/src/runtime/proc.go:201
7 0x000000000045d9c1 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:1333
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I’m not mistaken, the overall process looks like this:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;it checks if we’re giving an already IP address or a hostname; if a hostname, then&lt;/li&gt;
&lt;li&gt;looks up the host using the local resolver according to the lookup order specified by the system; then,&lt;/li&gt;
&lt;li&gt;eventually performs an actual DNS request asking for records for such domain; then,&lt;/li&gt;
&lt;li&gt;if all of that succeeds, a list of IP addresses is retrieved and then sorted out according to an &lt;a href="https://tools.ietf.org/html/rfc6724"&gt;RFC&lt;/a&gt;; which gives us the highest priority IP from the list.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Follow the stack trace above and you should be able to see by yourself the source code where the “magic” happens (it’s an interesting thing to do!).&lt;/p&gt;

&lt;p&gt;With an IP address chosen, we can proceed.&lt;/p&gt;

&lt;p&gt;note.: this process is &lt;strong&gt;not&lt;/strong&gt; different for TCP.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The book &lt;a href="https://amzn.to/2DEiNOG"&gt;Computer Networking: A top-down approach&lt;/a&gt; has a great section about DNS.&lt;/p&gt;

&lt;p&gt;I’d &lt;strong&gt;really&lt;/strong&gt; recommend you going through it to know more about.&lt;/p&gt;

&lt;p&gt;I also wrote a blog post about writing something that is able to resolve &lt;code&gt;A&lt;/code&gt; records from scratch using Go: &lt;a href="https://ops.tips/blog/dmesg-under-the-hood/"&gt;Writing DNS messages from scratch using Go&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  TCP Dialing vs UDP Dialing
&lt;/h3&gt;

&lt;p&gt;Instead of using a regular &lt;a href="https://golang.org/pkg/net/#Dial"&gt;&lt;code&gt;Dial&lt;/code&gt;&lt;/a&gt; commonly used with TCP, for our UDP client, a different method was used: &lt;a href="https://golang.org/pkg/net/#DialUDP"&gt;&lt;code&gt;DialUDP&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The reason for that is that we can enforce the type of address passed, as well as receive a specialized connection: the “concrete type” &lt;a href="https://golang.org/pkg/net/#UDPConn"&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt; instead of the generic &lt;a href="https://golang.org/pkg/net/#Conn"&gt;&lt;code&gt;Conn&lt;/code&gt;&lt;/a&gt; interface.&lt;/p&gt;

&lt;p&gt;Although both &lt;code&gt;Dial&lt;/code&gt; and &lt;code&gt;DialUDP&lt;/code&gt; might sound like the same (even when it comes to the syscalls used while talking to the kernel), they end up being pretty different concerning the network stack implementation.&lt;/p&gt;

&lt;p&gt;For instance, we can check that both methods use &lt;a href="http://man7.org/linux/man-pages/man2/connect.2.html"&gt;&lt;code&gt;connect(2)&lt;/code&gt;&lt;/a&gt; under the hood:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;TCP
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// TCP - performs an actual `connect` under the hood,&lt;/span&gt;
&lt;span class="c"&gt;// trying to establish an actual connection with the&lt;/span&gt;
&lt;span class="c"&gt;// other side.&lt;/span&gt;
&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"tcp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1.1.1.1:53"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// strace -f -e trace=network ./main&lt;/span&gt;
&lt;span class="c"&gt;// [pid 4891] socket(&lt;/span&gt;
        &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="o"&gt;-----&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SOCK_STREAM&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;SOCK_NONBLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;IPPROTO_IP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="c"&gt;// [pid 4891] connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("1.1.1.1")}, 16) = -1 EINPROGRESS (Operation now in progress)&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;UDP
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// UDP - calls `connect` just like TCP, but given that&lt;/span&gt;
&lt;span class="c"&gt;// the arguments are different (it's not SOCK_STREAM),&lt;/span&gt;
&lt;span class="c"&gt;// the semantics differ - it constrains the socket &lt;/span&gt;
&lt;span class="c"&gt;// regarding to whom it might communicate with.&lt;/span&gt;
&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"1.1.1.1:53"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// strace -f -e trace=network ./main&lt;/span&gt;
&lt;span class="c"&gt;// [pid 5517] socket(&lt;/span&gt;
        &lt;span class="n"&gt;AF_INET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
 &lt;span class="o"&gt;-----&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;SOCK_DGRAM&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;SOCK_CLOEXEC&lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;&lt;span class="n"&gt;SOCK_NONBLOCK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; 
        &lt;span class="n"&gt;IPPROTO_IP&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;3&lt;/span&gt;
&lt;span class="c"&gt;// [pid 5517] connect(3, {sa_family=AF_INET, sin_port=htons(53), sin_addr=inet_addr("1.1.1.1")}, 16) = 0&lt;/span&gt;
&lt;span class="o"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While they’re pretty much the same, from the documentation we can see how they are semantically different depending on the way we configure the &lt;code&gt;socket&lt;/code&gt; created via the &lt;code&gt;socket(2)&lt;/code&gt; call that happens before &lt;code&gt;connect(2)&lt;/code&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If the socket sockfd is of type &lt;strong&gt;SOCK_DGRAM&lt;/strong&gt; , then addr is the address to which datagrams are sent by default, and the only address from which datagrams are received.&lt;/p&gt;

&lt;p&gt;If the socket is of type &lt;strong&gt;SOCK_STREAM&lt;/strong&gt; or SOCK_SEQ‐PACKET, this call attempts to make a connection to the socket that is bound to the address specified by addr.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Should we be able to verify that with the TCP transport the &lt;code&gt;Dial&lt;/code&gt; method would perform the act of really connecting to the other side? Sure!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/funccount &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;pidof main&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="s1"&gt;'tcp_*'&lt;/span&gt;
Tracing 316 functions &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="s2"&gt;"tcp_*"&lt;/span&gt;... Hit Ctrl-C to end.
^C
FUNC COUNT
tcp_small_queue_check.isra.28 1
tcp_current_mss 1
tcp_schedule_loss_probe 1
tcp_mss_to_mtu 1
tcp_write_queue_purge 1
tcp_write_xmit 1
tcp_select_initial_window 1
tcp_fastopen_defer_connect 1
tcp_mtup_init 1
tcp_v4_connect 1
tcp_v4_init_sock 1
tcp_rearm_rto.part.61 1
tcp_close 1
tcp_connect 1
tcp_send_fin 1
tcp_rearm_rto 1
tcp_tso_segs 1
tcp_event_new_data_sent 1
tcp_check_oom 1
tcp_clear_retrans 1
tcp_init_xmit_timers 1
tcp_init_sock 1
tcp_initialize_rcv_mss 1
tcp_assign_congestion_control 1
tcp_sync_mss 1
tcp_init_tso_segs 1
tcp_stream_memory_free 1
tcp_setsockopt 1
tcp_chrono_stop 2
tcp_rbtree_insert 2
tcp_set_state 2
tcp_established_options 2
tcp_transmit_skb 2
tcp_v4_send_check 2
tcp_rate_skb_sent 2
tcp_options_write 2
tcp_poll 2
tcp_release_cb 4
tcp_v4_md5_lookup 4
tcp_md5_do_lookup 4
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In the case of UDP though, in theory, it merely takes care of marking the socket for reads and writes to the specified address.&lt;/p&gt;

&lt;p&gt;Going through the same process that we did for TCP (going further from looking at the syscall interface), we can trace the underlying kernel methods used by both &lt;code&gt;DialUDP&lt;/code&gt; and &lt;code&gt;Dial&lt;/code&gt; to see how they differ:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;./tools/funccount &lt;span class="nt"&gt;-p&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;pidof main&lt;span class="si"&gt;)&lt;/span&gt; &lt;span class="s1"&gt;'udp_*'&lt;/span&gt;
Tracing 57 functions &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="s2"&gt;"udp_*"&lt;/span&gt;... Hit Ctrl-C to end.
^C
FUNC COUNT
udp_v4_rehash 1
udp_poll 1
udp_v4_get_port 1
udp_lib_close 1
udp_lib_lport_inuse 1
udp_init_sock 1
udp_lib_unhash 1
udp_lib_rehash 1
udp_lib_get_port 1
udp_destroy_sock 1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Much… Much less.&lt;/p&gt;

&lt;p&gt;If we go even further, try to explore what happens at each of these calls, we can notice how &lt;code&gt;connect(2)&lt;/code&gt; in the case of TCP ends up really transmitting data (to establish perform the handshake, for instance):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PID TID COMM FUNC
6747 6749 main tcp_transmit_skb
        tcp_transmit_skb+0x1
        tcp_v4_connect+0x3f5
        __inet_stream_connect+0x238
        inet_stream_connect+0x3b
        SYSC_connect+0x9e
        sys_connect+0xe
        do_syscall_64+0x73
        entry_SYSCALL_64_after_hwframe+0x3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;While in the case of UDP, nothing is transmitted, just some set up is performed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PID TID COMM FUNC
6815 6817 main ip4_datagram_connect
        ip4_datagram_connect+0x1 &lt;span class="o"&gt;[&lt;/span&gt;kernel]
        SYSC_connect+0x9e &lt;span class="o"&gt;[&lt;/span&gt;kernel]
        sys_connect+0xe &lt;span class="o"&gt;[&lt;/span&gt;kernel]
        do_syscall_64+0x73 &lt;span class="o"&gt;[&lt;/span&gt;kernel]
        entry_SYSCALL_64_after_hwframe+0x3d &lt;span class="o"&gt;[&lt;/span&gt;kernel]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you’re not convinced yet that these two are &lt;strong&gt;really&lt;/strong&gt; different (in the sense that the TCP one sends packets to establish the connection, while UDP doesn’t), we can set up some triggers in the network stack to tell us whenever packets flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# By creating a rule that will only match&lt;/span&gt;
&lt;span class="c"&gt;# packets destined at `1.1.1.1` and that&lt;/span&gt;
&lt;span class="c"&gt;# match a specific protocol, we're able&lt;/span&gt;
&lt;span class="c"&gt;# to see what happens at the time that&lt;/span&gt;
&lt;span class="c"&gt;# `connect(2)` happens with a given protocol&lt;/span&gt;
&lt;span class="c"&gt;# or another.&lt;/span&gt;
iptables &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--table&lt;/span&gt; filter &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--insert&lt;/span&gt; OUTPUT &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--jump&lt;/span&gt; LOG &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--protocol&lt;/span&gt; udp &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--destination&lt;/span&gt; 1.1.1.1 &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--log-prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[UDP] "&lt;/span&gt;

iptables &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--table&lt;/span&gt; filter &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--insert&lt;/span&gt; OUTPUT &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--jump&lt;/span&gt; LOG &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--protocol&lt;/span&gt; tcp &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--destination&lt;/span&gt; 1.1.1.1 &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--log-prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[TCP] "&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, run &lt;code&gt;Dial&lt;/code&gt; against a TCP target and &lt;code&gt;DialUDP&lt;/code&gt; target and compare the differences.&lt;/p&gt;

&lt;p&gt;You should only see &lt;code&gt;[TCP]&lt;/code&gt; logs:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="o"&gt;[&lt;/span&gt;46260.105662] &lt;span class="o"&gt;[&lt;/span&gt;TCP] &lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;enp0s3 &lt;span class="nv"&gt;DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.1.1.1 SYN &lt;span class="nv"&gt;URGP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="o"&gt;[&lt;/span&gt;46260.120454] &lt;span class="o"&gt;[&lt;/span&gt;TCP] &lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;enp0s3 &lt;span class="nv"&gt;DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.1.1.1 ACK &lt;span class="nv"&gt;URGP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="o"&gt;[&lt;/span&gt;46260.120718] &lt;span class="o"&gt;[&lt;/span&gt;TCP] &lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;enp0s3 &lt;span class="nv"&gt;DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.1.1.1 ACK FIN &lt;span class="nv"&gt;URGP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;span class="o"&gt;[&lt;/span&gt;46260.150452] &lt;span class="o"&gt;[&lt;/span&gt;TCP] &lt;span class="nv"&gt;IN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;enp0s3 &lt;span class="nv"&gt;DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1.1.1.1 ACK &lt;span class="nv"&gt;URGP&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;If you’re not familiar with the inner workings of &lt;code&gt;dmesg&lt;/code&gt;, check out my other blog post - &lt;a href="https://ops.tips/blog/dmesg-under-the-hood"&gt;dmesg under the hood&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;By the way, &lt;a href="https://amzn.to/2QWyXp9"&gt;The Linux Programming Interface&lt;/a&gt; is a great book to know more about sockets and other related topics!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Writing to a UDP “connection”
&lt;/h3&gt;

&lt;p&gt;With our UDP socket properly created and configured for a specific address, we’re now on time to go through the “write” path - when we actually take some data and write to the &lt;code&gt;UDPConn&lt;/code&gt; object received from &lt;code&gt;net.DialUDP&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A sample program that just sends a little bit of data to a given UDP server would be as follow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// Perform the address resolution and also&lt;/span&gt;
&lt;span class="c"&gt;// specialize the socket to only be able&lt;/span&gt;
&lt;span class="c"&gt;// to read and write to and from such&lt;/span&gt;
&lt;span class="c"&gt;// resolved address.&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Dial&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;addr&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

&lt;span class="c"&gt;// Call the `Write()` method of the implementor&lt;/span&gt;
&lt;span class="c"&gt;// of the `io.Writer` interface.&lt;/span&gt;
&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Fprintf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"something"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Given that &lt;code&gt;conn&lt;/code&gt; returned by &lt;code&gt;Dial&lt;/code&gt; implements the &lt;code&gt;io.Writer&lt;/code&gt; interface, we can make use of something like &lt;code&gt;fmt.Fprintf&lt;/code&gt; (that takes an &lt;code&gt;io.Writer&lt;/code&gt; as its first argument) as let it call &lt;code&gt;Write()&lt;/code&gt; with the message we pass to it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;If interfaces and other Golang concepts are not clear for you yet, make sure you check Kernighan’s book: &lt;a href="https://amzn.to/2R7XdVe"&gt;The Go Programming Language&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;yeah, from the guy who wrote &lt;a href="https://amzn.to/2zE5jOV"&gt;The C Programming Language&lt;/a&gt; with Dennis Ritchie&lt;/em&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Under the hood, &lt;a href="https://golang.org/pkg/net/#UDPConn"&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt; implements the &lt;code&gt;Write()&lt;/code&gt; method from the &lt;a href="https://golang.org/pkg/io/#Writer"&gt;&lt;code&gt;io.Writer&lt;/code&gt;&lt;/a&gt; interface by being a composition of &lt;a href="https://github.com/golang/go/blob/a0e7f12771c2e84e626dcf5e30da5d62a3b1adf6/src/net/net.go#L164-L166"&gt;&lt;code&gt;conn&lt;/code&gt;&lt;/a&gt;, a struct that implements the most basic methods regarding writing to and reading from a given file descriptor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;fd&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;netFD&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// Write implements the Conn Write method.&lt;/span&gt;
&lt;span class="k"&gt;func&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;*&lt;/span&gt;&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;Write&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="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;syscall&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EINVAL&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Write&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="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;OpError&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Op&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="s"&gt;"write"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Net&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Source&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;laddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Addr&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c"&gt;// UDPConn is the implementation of the Conn &lt;/span&gt;
&lt;span class="c"&gt;// and PacketConn interfaces for UDP network &lt;/span&gt;
&lt;span class="c"&gt;// connections.&lt;/span&gt;
&lt;span class="k"&gt;type&lt;/span&gt; &lt;span class="n"&gt;UDPConn&lt;/span&gt; &lt;span class="k"&gt;struct&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;conn&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, knowing that in the end &lt;code&gt;fmt.Fprintf(conn, "something")&lt;/code&gt; ends up in a &lt;code&gt;write(2)&lt;/code&gt; to a file descriptor (the UDP socket), we can investigate even further and see how does the kernel path look for such &lt;code&gt;write(2)&lt;/code&gt; call:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;PID TID COMM FUNC
14502 14502 write.out ip_send_skb
        ip_send_skb+0x1 
        udp_sendmsg+0x3b5 
        inet_sendmsg+0x2e 
        sock_sendmsg+0x3e 
        sock_write_iter+0x8c 
        new_sync_write+0xe7 
        __vfs_write+0x29 
        vfs_write+0xb1 
        sys_write+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At that point, the packet should be on its way to the other side of the communication channel.&lt;/p&gt;

&lt;h3&gt;
  
  
  Receiving from a UDP “connection” in a client
&lt;/h3&gt;

&lt;p&gt;The act of receiving from &lt;code&gt;UDPConn&lt;/code&gt; can be seen as pretty much the same as the “write path”, except that at this time, a buffer is supplied (so that it can get filled with the contents that arrive), and we don’t really know how long we have to wait for the content to arrive.&lt;/p&gt;

&lt;p&gt;For instance, we could have the following code path for reading from a known address:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufSize&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;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This would turn into a &lt;code&gt;read(2)&lt;/code&gt; syscall under the hood, which would then go through &lt;code&gt;vfs&lt;/code&gt; and turn into a &lt;code&gt;read&lt;/code&gt; from a socket:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;22313 22313 &lt;span class="nb"&gt;read &lt;/span&gt;__skb_recv_udp
        __skb_recv_udp+0x1 
        inet_recvmsg+0x51 
        sock_recvmsg+0x43 
        sock_read_iter+0x90 
        new_sync_read+0xe4 
        __vfs_read+0x29 
        vfs_read+0x8e 
        sys_read+0x55 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Something important to remember is that when it comes to reading from the socket, that’s going to be a blocking operation.&lt;/p&gt;

&lt;p&gt;Given that a message might never return from such socket, we can get stuck waiting forever.&lt;/p&gt;

&lt;p&gt;To avoid such situation, we can set a reading deadline that would kill the whole thing in case we wait for too long:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;bufSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Sets the read deadline for now + 15seconds.&lt;/span&gt;
&lt;span class="c"&gt;// If you plan to read from the same connection again,&lt;/span&gt;
&lt;span class="c"&gt;// make sure you expand the deadline before reading&lt;/span&gt;
&lt;span class="c"&gt;// it.&lt;/span&gt;
&lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetReadDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;15&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Second&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;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;conn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now, In case the other end takes too long to answer:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;read &lt;/span&gt;udp 10.0.2.15:41745-&amp;gt;1.1.1.1:53: i/o &lt;span class="nb"&gt;timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Receiving from a UDP “connection” in a server
&lt;/h3&gt;

&lt;p&gt;While that’s great for the &lt;code&gt;client&lt;/code&gt; (we know whom we’re reading from), it’s not for a server.&lt;/p&gt;

&lt;p&gt;The reason why is that at the server side, we don’t know who we’re reading from (the address is unknown).&lt;/p&gt;

&lt;p&gt;Differently from the case of a TCP server where we have &lt;code&gt;accept(2)&lt;/code&gt; which returns to the server implementor the connection that the server can write to, in the case of UDP, there’s no such thing as a “connection to write to”. There’s only a “whom to write to”, that can be retrieved by inspecting the packet that arrived.&lt;br&gt;
&lt;/p&gt;

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

  "Hmmm, let me write something to
   my buddy at 1.1.1.1:53"

   client --.
            |
            | client: n, err := udpConn.Write(buf)
            | server: n, err := udpConn.Read(buf)
            |
            *---&amp;gt; server
                  "Oh, somebody wrote me something!
                   I'd like to write back to him/her,
                   but, what's his/her address?

                   I don't have a connection... I need
                   an address to write to! I can't to
                   a thing now!"



WITH READFROM

   client --.
            |
            | client: n, err := udpConn.Write(buf)
            | server: n, address, err := udpConn.Read(buf)
            |
            *---&amp;gt; server
                  "Oh, looking at the packet, I can
                   see that my friend Jane wrote to me,
                   I can see that from `address`!

                   Let me answer her back!"
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For that reason, on the server, we need the specialized connection: &lt;a href="https://golang.org/pkg/net/#UDPConn"&gt;&lt;code&gt;UDPConn&lt;/code&gt;&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Such specialized connection is able of giving us &lt;code&gt;ReadFrom&lt;/code&gt;, a method that instead of just reading from a file descriptor and adding the contents to a buffer, it also inspects the headers of the packet and gives us information about who sent the package.&lt;/p&gt;

&lt;p&gt;Its usage looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// Given a buffer that is meant to hold the&lt;/span&gt;
&lt;span class="c"&gt;// contents from the messages arriving at the&lt;/span&gt;
&lt;span class="c"&gt;// socket that `udpConn` wraps, it blocks until&lt;/span&gt;
&lt;span class="c"&gt;// messages arrive. &lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// For each message arriving, `ReadFrom` unwraps&lt;/span&gt;
&lt;span class="c"&gt;// the message, getting information about the&lt;/span&gt;
&lt;span class="c"&gt;// sender from the protocol headers and then&lt;/span&gt;
&lt;span class="c"&gt;// fills the buffer with the data.&lt;/span&gt;
&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;udpConn&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;panic&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&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;An interesting way of trying to understand how things work under the hood is looking at the &lt;a href="https://en.wikipedia.org/wiki/Plan_9_from_Bell_Labs"&gt;plan9&lt;/a&gt; implementation (&lt;a href="https://github.com/golang/go/blob/a0e7f12771c2e84e626dcf5e30da5d62a3b1adf6/src/net/udpsock_plan9.go#L14-L28"&gt;&lt;code&gt;net/udpsock_plan9.go&lt;/code&gt;&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;Here’s how it looks (with comments of my own):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="k"&gt;func&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;*&lt;/span&gt;&lt;span class="n"&gt;UDPConn&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;readFrom&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="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;UDPAddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// creates a buffer a little bit bigger than&lt;/span&gt;
        &lt;span class="c"&gt;// the one we provided (to account for the header of&lt;/span&gt;
        &lt;span class="c"&gt;// the UDP headers)&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;udpHeaderSize&lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="nb"&gt;len&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="c"&gt;// reads from the underlying file descriptor (this might&lt;/span&gt;
        &lt;span class="c"&gt;// block).&lt;/span&gt;
    &lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;fd&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&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;m&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;udpHeaderSize&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;errors&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;New&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"short read reading UDP header"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// strips out the parts that were not readen&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;

        &lt;span class="c"&gt;// interprets the UDP header&lt;/span&gt;
    &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;unmarshalUDPHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

        &lt;span class="c"&gt;// copies the data back to our supplied buffer&lt;/span&gt;
        &lt;span class="c"&gt;// so that we only receive the data, not the header.&lt;/span&gt;
    &lt;span class="n"&gt;n&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;copy&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="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;n&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;UDPAddr&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;IP&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;raddr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Port&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;h&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;rport&lt;/span&gt;&lt;span class="p"&gt;)},&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Naturally, under Linux, that’s not the path that &lt;code&gt;readFrom&lt;/code&gt; takes. It uses &lt;code&gt;recvfrom&lt;/code&gt; which does the whole “UDP header interpretation” under the hood, but the idea is the same (except that with &lt;code&gt;plan9&lt;/code&gt; it’s all done in userspace).&lt;/p&gt;

&lt;p&gt;To verify the fact that under Linux we’re using &lt;code&gt;recvfrom&lt;/code&gt;, we trace &lt;code&gt;UDPConn.ReadFrom&lt;/code&gt; down (you can use &lt;a href="https://github.com/derekparker/delve"&gt;&lt;code&gt;delve&lt;/code&gt;&lt;/a&gt; for that):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;0 0x00000000004805b8 in syscall.recvfrom
   at /usr/local/go/src/syscall/zsyscall_linux_amd64.go:1641
1 0x000000000047e84f in syscall.Recvfrom
   at /usr/local/go/src/syscall/syscall_unix.go:262
2 0x0000000000494281 in internal/poll.(*FD).ReadFrom
   at /usr/local/go/src/internal/poll/fd_unix.go:215
3 0x00000000004f5f4e in net.(*netFD).readFrom
   at /usr/local/go/src/net/fd_unix.go:208
4 0x0000000000516ab1 in net.(*UDPConn).readFrom
   at /usr/local/go/src/net/udpsock_posix.go:47
5 0x00000000005150a4 in net.(*UDPConn).ReadFrom
   at /usr/local/go/src/net/udpsock.go:121
6 0x0000000000526bbf in main.server.func1
   at ./main.go:65
7 0x000000000045e1d1 in runtime.goexit
   at /usr/local/go/src/runtime/asm_amd64.s:1333
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the kernel level, we can also check what are the methods involved:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;24167 24167 go-sample-udp __skb_recv_udp
        __skb_recv_udp+0x1 
        inet_recvmsg+0x51 
        sock_recvmsg+0x43 
        SYSC_recvfrom+0xe4 
        sys_recvfrom+0xe 
        do_syscall_64+0x73 
        entry_SYSCALL_64_after_hwframe+0x3d
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  A UDP Server in Go
&lt;/h3&gt;

&lt;p&gt;Now, going to the server-side implementation, here’s how the code would look like (heavily commented):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// maxBufferSize specifies the size of the buffers that&lt;/span&gt;
&lt;span class="c"&gt;// are used to temporarily hold data from the UDP packets&lt;/span&gt;
&lt;span class="c"&gt;// that we receive.&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;maxBufferSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;

&lt;span class="c"&gt;// server wraps all the UDP echo server functionality.&lt;/span&gt;
&lt;span class="c"&gt;// ps.: the server is capable of answering to a single&lt;/span&gt;
&lt;span class="c"&gt;// client at a time.&lt;/span&gt;
&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;server&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt; &lt;span class="n"&gt;context&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Context&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c"&gt;// ListenPacket provides us a wrapper around ListenUDP so that&lt;/span&gt;
    &lt;span class="c"&gt;// we don't need to call `net.ResolveUDPAddr` and then subsequentially&lt;/span&gt;
    &lt;span class="c"&gt;// perform a `ListenUDP` with the UDP address.&lt;/span&gt;
    &lt;span class="c"&gt;//&lt;/span&gt;
    &lt;span class="c"&gt;// The returned value (PacketConn) is pretty much the same as the one&lt;/span&gt;
    &lt;span class="c"&gt;// from ListenUDP (UDPConn) - the only difference is that `Packet*`&lt;/span&gt;
    &lt;span class="c"&gt;// methods and interfaces are more broad, also covering `ip`.&lt;/span&gt;
    &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;net&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ListenPacket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"udp"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;address&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c"&gt;// `Close`ing the packet "connection" means cleaning the data structures&lt;/span&gt;
    &lt;span class="c"&gt;// allocated for holding information about the listening socket.&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Close&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;

    &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;chan&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;buffer&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;maxBufferSize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

    &lt;span class="c"&gt;// Given that waiting for packets to arrive is blocking by nature and we want&lt;/span&gt;
    &lt;span class="c"&gt;// to be able of canceling such action if desired, we do that in a separate&lt;/span&gt;
    &lt;span class="c"&gt;// go routine.&lt;/span&gt;
    &lt;span class="k"&gt;go&lt;/span&gt; &lt;span class="k"&gt;func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c"&gt;// By reading from the connection into the buffer, we block until there's&lt;/span&gt;
            &lt;span class="c"&gt;// new content in the socket that we're listening for new packets.&lt;/span&gt;
            &lt;span class="c"&gt;//&lt;/span&gt;
            &lt;span class="c"&gt;// Whenever new packets arrive, `buffer` gets filled and we can continue&lt;/span&gt;
            &lt;span class="c"&gt;// the execution.&lt;/span&gt;
            &lt;span class="c"&gt;//&lt;/span&gt;
            &lt;span class="c"&gt;// note.: `buffer` is not being reset between runs.&lt;/span&gt;
            &lt;span class="c"&gt;// It's expected that only `n` reads are read from it whenever&lt;/span&gt;
            &lt;span class="c"&gt;// inspecting its contents.&lt;/span&gt;
            &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ReadFrom&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"packet-received: bytes=%d from=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;

            &lt;span class="c"&gt;// Setting a deadline for the `write` operation allows us to not block&lt;/span&gt;
            &lt;span class="c"&gt;// for longer than a specific timeout.&lt;/span&gt;
            &lt;span class="c"&gt;//&lt;/span&gt;
            &lt;span class="c"&gt;// In the case of a write operation, that'd mean waiting for the send&lt;/span&gt;
            &lt;span class="c"&gt;// queue to be freed enough so that we are able to proceed.&lt;/span&gt;
            &lt;span class="n"&gt;deadline&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Now&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;timeout&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SetWriteDeadline&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;deadline&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="c"&gt;// Write the packet's contents back to the client.&lt;/span&gt;
            &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WriteTo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;addr&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;err&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="no"&gt;nil&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;doneChan&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;
                &lt;span class="k"&gt;return&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Printf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"packet-written: bytes=%d to=%s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;addr&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;String&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="k"&gt;select&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Done&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
        &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Println&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"cancelled"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ctx&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Err&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;case&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;-&lt;/span&gt;&lt;span class="n"&gt;doneChan&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you might have noticed, it’s not all that different from the client! The reason why is that not having an actual connection involved (like in TCP), both client and servers end up going through the same path: preparing a socket to read and write from and to, then checking the content from the packets and doing the same thing over and over again.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing thoughts
&lt;/h3&gt;

&lt;p&gt;It was great to go through this exploration, checking what’s going on behind the scenes in the Go source code (very well written, by the way), as well as in the Kernel.&lt;/p&gt;

&lt;p&gt;I think I finally got a great workflow when it comes to debugging with &lt;a href="https://github.com/derekparker/delve"&gt;Delve&lt;/a&gt; and verifying the Kernel functions with &lt;a href="https://github.com/iovisor/bcc"&gt;bcc&lt;/a&gt;, maybe I’ll write about that soon - let me know if that’d be interesting!&lt;/p&gt;

&lt;p&gt;If you have any questions, please let me know! I’m &lt;a href="https://twitter.com/cirowrc"&gt;@cirowrc&lt;/a&gt; on Twitter, and I’d love to receive your feedback.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>networking</category>
      <category>go</category>
    </item>
    <item>
      <title>Retrieving the full path of a process on MacOS (and exploring procfs)</title>
      <dc:creator>Ciro S. Costa</dc:creator>
      <pubDate>Tue, 25 Sep 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/cirowrc/retrieving-the-full-path-of-a-process-on-macos-and-exploring-procfs-7gi</link>
      <guid>https://dev.to/cirowrc/retrieving-the-full-path-of-a-process-on-macos-and-exploring-procfs-7gi</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;Another day I was trying to make sure that a given process that I was running was using a specific binary that I had built, but I couldn’t figure out: &lt;code&gt;ps&lt;/code&gt; would only show me the non-absolute path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# How could I know what is the absolute path of the&lt;/span&gt;
&lt;span class="c"&gt;# `hugo` binary, assuming that I could have multiple&lt;/span&gt;
&lt;span class="c"&gt;# `hugo` binaries in `$PATH`?&lt;/span&gt;
ps
  PID TTY TIME CMD
 4153 ttys000 5:14.98 hugo serve &lt;span class="o"&gt;&amp;lt;&amp;lt;&amp;lt;&lt;/span&gt;
 9035 ttys001 0:00.04 /Applications/iTerm.app/Content...
 9037 ttys001 0:00.10 &lt;span class="nt"&gt;-bash&lt;/span&gt;
 9086 ttys001 0:02.27 /usr/local/Cellar/macvim/8.1-15...
 9236 ttys002 0:00.04 /Applications/iTerm.app/Content...
 9238 ttys002 0:00.10 &lt;span class="nt"&gt;-bash&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If I were using Linux though, I thought, that’d be easy: head to &lt;code&gt;/proc&lt;/code&gt;, search for the &lt;code&gt;pid&lt;/code&gt; of the process and then check what &lt;code&gt;exe&lt;/code&gt; links to; done.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# (on a Linux machine ...)&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# See `hugo` will still not show up with the absolute path&lt;/span&gt;
&lt;span class="c"&gt;# like on MacOS.&lt;/span&gt;
ps aux | &lt;span class="nb"&gt;grep &lt;/span&gt;hugo
ubuntu 2275 0.0 0.0 101852 748 pts/0 Sl+ 00:26 0:00 hugo serve

&lt;span class="c"&gt;# Given that the proc filesystem can provide us with some&lt;/span&gt;
&lt;span class="c"&gt;# more information about the process, check out the `exe`&lt;/span&gt;
&lt;span class="c"&gt;# link (which should provide a link to the actual executable).&lt;/span&gt;
&lt;span class="nb"&gt;stat&lt;/span&gt; /proc/2275/exe
  File: /proc/2275/exe -&amp;gt; /usr/local/bin/hugo
  Size: 0 Blocks: 0 IO Block: 1024 symbolic &lt;span class="nb"&gt;link
&lt;/span&gt;Device: 4h/4d   Inode: 140106 Links: 1
Access: &lt;span class="o"&gt;(&lt;/span&gt;0777/lrwxrwxrwx&lt;span class="o"&gt;)&lt;/span&gt; Uid: &lt;span class="o"&gt;(&lt;/span&gt; 1001/ ubuntu&lt;span class="o"&gt;)&lt;/span&gt; Gid: &lt;span class="o"&gt;(&lt;/span&gt; 1001/ ubuntu&lt;span class="o"&gt;)&lt;/span&gt;
Access: 2018-09-24 00:26:37.167004005 +0000
Modify: 2018-09-24 00:26:27.391004005 +0000
Change: 2018-09-24 00:26:27.391004005 +0000
 Birth: -
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In this post, I go through how we can gather such information on a MacOS, and what the &lt;code&gt;procfs&lt;/code&gt; in Linux is all about.&lt;/p&gt;

&lt;p&gt;&lt;em&gt;tl;dr: &lt;code&gt;/proc&lt;/code&gt; on Linux is dope; on MacoS: compile a little code that uses &lt;a href="https://opensource.apple.com/source/xnu/xnu-2422.1.72/libsyscall/wrappers/libproc/libproc.h.auto.html"&gt;&lt;code&gt;proc_pidpath&lt;/code&gt;&lt;/a&gt; from &lt;code&gt;libproc&lt;/code&gt;, or install &lt;a href="https://github.com/cirocosta/pidpath"&gt;&lt;code&gt;pidpath&lt;/code&gt;&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  The /proc filesystem in Linux
&lt;/h3&gt;

&lt;p&gt;In “Linux land”, there’s this thing called “procfs”.&lt;/p&gt;

&lt;p&gt;It’s a virtual filesystem - in the sense that there are no real regular files in your disk that map to the filesystem representation - that allows a user (in userspace) to perform some introspection about its current running process and others as well.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://www.kernel.org/doc/Documentation/filesystems/proc.txt"&gt;the kernel docs&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The proc file system acts as an interface to internal data structures in the kernel.&lt;/p&gt;

&lt;p&gt;It can be used to obtain information about the system and to change certain kernel parameters at runtime (&lt;a href="https://linux.die.net/man/8/sysctl"&gt;sysctl&lt;/a&gt;).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The way the interaction with it is set up is pretty nifty:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;each process receives a given path under &lt;code&gt;/proc&lt;/code&gt; (like, &lt;code&gt;/proc/&amp;lt;pid&amp;gt;&lt;/code&gt;), and then&lt;/li&gt;
&lt;li&gt;as subdirectories of this path, various other files and subdirectories are present to allow deeper introspection about the specific pid.
&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Display the files and directories present at the&lt;/span&gt;
&lt;span class="c"&gt;# very root of `/proc`.&lt;/span&gt;
&lt;span class="c"&gt;#&lt;/span&gt;
&lt;span class="c"&gt;# Here we can find the list of PIDs that we can access,&lt;/span&gt;
&lt;span class="c"&gt;# as well as some more system-wide information and &lt;/span&gt;
&lt;span class="c"&gt;# settings that we can tweak.&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lah&lt;/span&gt; /proc
total 4.0K
dr-xr-xr-x 124 root root 0 Sep 24 23:56 &lt;span class="nb"&gt;.&lt;/span&gt;
drwxr-xr-x 24 root root 4.0K Sep 24 23:57 ..
dr-xr-xr-x 9 root root 0 Sep 24 23:56 1
dr-xr-xr-x 9 root root 0 Sep 25 00:54 2016
dr-xr-xr-x 9 root root 0 Sep 24 23:57 417
...
&lt;span class="nt"&gt;-r--r--r--&lt;/span&gt; 1 root root 0 Sep 25 01:25 sched_debug
&lt;span class="nt"&gt;-r--r--r--&lt;/span&gt; 1 root root 0 Sep 25 01:25 schedstat
dr-xr-xr-x 4 root root 0 Sep 25 01:25 scsi
lrwxrwxrwx 1 root root 0 Sep 24 23:56 self -&amp;gt; 2574
...

&lt;span class="c"&gt;# Getting into a specific pid path, we're able to&lt;/span&gt;
&lt;span class="c"&gt;# gather more information about the specifics of&lt;/span&gt;
&lt;span class="c"&gt;# a given process.&lt;/span&gt;
&lt;span class="nb"&gt;ls&lt;/span&gt; &lt;span class="nt"&gt;-lah&lt;/span&gt; /proc/472
total 0
dr-xr-xr-x 9 root root 0 Sep 24 23:57 &lt;span class="nb"&gt;.&lt;/span&gt;
dr-xr-xr-x 123 root root 0 Sep 24 23:56 ..
...
lrwxrwxrwx 1 root root 0 Sep 25 01:30 cwd -&amp;gt; /
&lt;span class="nt"&gt;-r--------&lt;/span&gt; 1 root root 0 Sep 25 01:30 environ
lrwxrwxrwx 1 root root 0 Sep 24 23:57 exe -&amp;gt; /lib/systemd/systemd-udevd
dr-x------ 2 root root 0 Sep 24 23:57 fd
lrwxrwxrwx 1 root root 0 Sep 25 01:30 root -&amp;gt; /
&lt;span class="nt"&gt;-rw-r--r--&lt;/span&gt; 1 root root 0 Sep 25 01:30 sched
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Not only that, &lt;code&gt;procfs&lt;/code&gt; is very helpful when you’re not sure if a process is blocked on something you didn’t expect (like a &lt;code&gt;write(2)&lt;/code&gt; to an &lt;code&gt;nfs&lt;/code&gt; mount point that is malformed due to a bad set of servers not responding), or something simple as your process sleeping when you didn’t want to:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Sleep for 33 days on the background&lt;/span&gt;
&lt;span class="nb"&gt;sleep &lt;/span&gt;33d &amp;amp;
&lt;span class="o"&gt;[&lt;/span&gt;1] 2786

&lt;span class="c"&gt;# Check what's the state of the process&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/2786/stat
2786 &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt; S ...
 | | |
 | | &lt;span class="sb"&gt;`&lt;/span&gt;-&amp;gt; state &lt;span class="o"&gt;(&lt;/span&gt;interruptible &lt;span class="nb"&gt;sleep&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 | &lt;span class="sb"&gt;`&lt;/span&gt;-&amp;gt; &lt;span class="nb"&gt;command &lt;/span&gt;being run &lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;sleep command&lt;/span&gt;&lt;span class="o"&gt;)&lt;/span&gt;
 &lt;span class="sb"&gt;`&lt;/span&gt;-&amp;gt; process &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="o"&gt;(&lt;/span&gt;the pid we used before&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Check what's the stack trace (from the kernel&lt;/span&gt;
&lt;span class="c"&gt;# perspective) that led the process to this &lt;/span&gt;
&lt;span class="c"&gt;# sleep state&lt;/span&gt;
&lt;span class="nb"&gt;cat&lt;/span&gt; /proc/2786/stack
&lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;] hrtimer_nanosleep+0xd8/0x1d0
&lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;] SyS_nanosleep+0x72/0xa0
&lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;] do_syscall_64+0x73/0x130
&lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;] entry_SYSCALL_64_after_hwframe+0x3d/0xa2
&lt;span class="o"&gt;[&lt;/span&gt;&amp;lt;0&amp;gt;] 0xffffffffffffffff
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  procfs under the hood
&lt;/h3&gt;

&lt;p&gt;What’s interesting about being virtual is that the implementation of &lt;code&gt;procfs&lt;/code&gt; is able to generate the representation of the filesystem on the fly - whenever you issue an I/O call like &lt;code&gt;read(2)&lt;/code&gt;, Linux answers back with what you asked for, be it the list of file descriptors opened by a given process, or the list of environment variables that were set at process startup time.&lt;/p&gt;

&lt;p&gt;For instance, if tracing the execution of &lt;code&gt;cat /proc/&amp;lt;pid&amp;gt;/meminfo&lt;/code&gt; down, we can find the path that the &lt;code&gt;read(2)&lt;/code&gt; syscall takes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# stack trace of `cat /proc/&amp;lt;pid&amp;gt;/meminfo`&lt;/span&gt;
        meminfo_proc_show
        proc_reg_read
        __vfs_read
        vfs_read
        sys_read
        do_syscall_64
        entry_SYSCALL_64_after_hwframe

&lt;span class="c"&gt;# stack trace of `cat /file.txt` &lt;/span&gt;
&lt;span class="c"&gt;# on an ext4 mount point&lt;/span&gt;
        ext4_file_read_iter
        __vfs_read
        vfs_read
        sys_read
        do_syscall_64
        entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Very different from a regular &lt;code&gt;read&lt;/code&gt; (as shown in the second stack trace), there’s no real file on disk being accessed - just &lt;code&gt;meminfo_proc_show&lt;/code&gt; returning the contents related to what the user asked for: virtual memory stuff.&lt;/p&gt;

&lt;p&gt;By the way, if you’re interested in knowing more about related subjects, a &lt;strong&gt;great&lt;/strong&gt; reference for this type of knowledge is &lt;a href="https://amzn.to/2QWyXp9"&gt;The Linux Programming Interface: A Linux and UNIX System Programming Handbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Now to MacOS.&lt;/p&gt;

&lt;h3&gt;
  
  
  The libproc library in MacOS
&lt;/h3&gt;

&lt;p&gt;Differently from Linux, it feels like we can’t know all that much about how things work on MacOS.&lt;/p&gt;

&lt;p&gt;After searching a bit on how to accomplish how to gather information about a process, &lt;code&gt;libproc&lt;/code&gt; showed up.&lt;/p&gt;

&lt;p&gt;As mentioned in &lt;a href="https://opensource.apple.com/source/xnu/xnu-2422.1.72/libsyscall/wrappers/libproc/libproc.h.auto.html"&gt;&lt;code&gt;libproc.h&lt;/code&gt;&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/*
 * This header file contains private interfaces 
 * to obtain process information.
 *
 * These interfaces are subject to change in future releases.
 */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;One thing to note:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;the interfaces are &lt;strong&gt;private&lt;/strong&gt; - no guaranteed compatibility with future releases.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This has been elucidated by an Apple staff member on &lt;a href="https://forums.developer.apple.com/thread/46963"&gt;post&lt;/a&gt; at the Apple’s developer forum regarding gathering process information:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;[…] Apple has not put a lot of effort into providing APIs for getting this sort of information.&lt;/p&gt;

&lt;p&gt;What APIs that do exist were either inherited from OS X’s predecessor OSs or were added &lt;strong&gt;primarily to meet our internal requirements rather than the needs for third-party developers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Thus, you will find a lot of places where these APIs are: incomplete; incorrect; poorly documented and aren’t as binary compatible as they should be.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Anyway, we can still make use of it - more specifically, we can make use of &lt;code&gt;proc_pidpath&lt;/code&gt;, a method that takes a &lt;code&gt;pid&lt;/code&gt; (the &lt;code&gt;pid&lt;/code&gt; of the process that we want to know more about), a buffer where the path should be written to, and the buffer size.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="nf"&gt;proc_pidpath&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
  &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// pid of the process to know more about&lt;/span&gt;
  &lt;span class="kt"&gt;void&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="n"&gt;buffer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// buffer to fill with the abs path&lt;/span&gt;
  &lt;span class="kt"&gt;uint32_t&lt;/span&gt; &lt;span class="n"&gt;buffersize&lt;/span&gt; &lt;span class="c1"&gt;// size of the buffer&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That said, we can go ahead and create our Go binary that can handle both Linux and MacOS by specifying two different compilation targets.&lt;/p&gt;

&lt;h3&gt;
  
  
  A Golang binary that suits Linux and MacOS
&lt;/h3&gt;

&lt;p&gt;Given that &lt;code&gt;libproc&lt;/code&gt; will not be a thing under Linux, we can start by creating a &lt;code&gt;pidpath_linux.go&lt;/code&gt; file that is meant to be compiled only on Linux, and another file, &lt;code&gt;pidpath_darwin.go&lt;/code&gt;, aimed at MacOS machines.&lt;/p&gt;

&lt;p&gt;The Linux one is rather simple: it follows the &lt;code&gt;/proc/&amp;lt;pid&amp;gt;/exe&lt;/code&gt; symlink, and that’s it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// +build linux&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"os"&lt;/span&gt;
    &lt;span class="s"&gt;"strconv"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetExePathFromPid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Readlink&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/proc/"&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="n"&gt;strconv&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Itoa&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;+&lt;/span&gt; &lt;span class="s"&gt;"/exe"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The MacOS version though, needs a little bit more.&lt;/p&gt;

&lt;p&gt;Given that we’d access &lt;code&gt;libproc&lt;/code&gt; via C, we can leverage &lt;a href="https://golang.org/cmd/cgo/"&gt;CGO&lt;/a&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight go"&gt;&lt;code&gt;&lt;span class="c"&gt;// +build darwin&lt;/span&gt;
&lt;span class="k"&gt;package&lt;/span&gt; &lt;span class="n"&gt;main&lt;/span&gt;

&lt;span class="c"&gt;// #include &amp;lt;libproc.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;// #include &amp;lt;stdlib.h&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;// #include &amp;lt;errno.h&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="s"&gt;"C"&lt;/span&gt;

&lt;span class="k"&gt;import&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"fmt"&lt;/span&gt;
    &lt;span class="s"&gt;"unsafe"&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;// bufSize references the constant that the implementation&lt;/span&gt;
&lt;span class="c"&gt;// of proc_pidpath uses under the hood to make sure that&lt;/span&gt;
&lt;span class="c"&gt;// no overflows happen.&lt;/span&gt;
&lt;span class="c"&gt;//&lt;/span&gt;
&lt;span class="c"&gt;// See https://opensource.apple.com/source/xnu/xnu-2782.40.9/libsyscall/wrappers/libproc/libproc.c&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt; &lt;span class="n"&gt;bufSize&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PROC_PIDPATHINFO_MAXSIZE&lt;/span&gt;

&lt;span class="k"&gt;func&lt;/span&gt; &lt;span class="n"&gt;GetExePathFromPid&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="kt"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c"&gt;// Allocate in the C heap a string (char* terminated&lt;/span&gt;
        &lt;span class="c"&gt;// with `/0`) of size `bufSize` and then make sure&lt;/span&gt;
        &lt;span class="c"&gt;// that we free that memory that gets allocated&lt;/span&gt;
        &lt;span class="c"&gt;// in C (see the `defer` below).&lt;/span&gt;
    &lt;span class="n"&gt;buf&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nb"&gt;make&lt;/span&gt;&lt;span class="p"&gt;([]&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;bufSize&lt;/span&gt;&lt;span class="p"&gt;)))&lt;/span&gt;
    &lt;span class="k"&gt;defer&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;free&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;

        &lt;span class="c"&gt;// Call the C function `proc_pidpath` from the included&lt;/span&gt;
        &lt;span class="c"&gt;// header file (libproc.h).&lt;/span&gt;
    &lt;span class="n"&gt;ret&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;:=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;proc_pidpath&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;.&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;unsafe&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pointer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="n"&gt;bufSize&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;ret&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;err&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;fmt&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Errorf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"failed to retrieve pid path: %v"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;err&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c"&gt;// Convert the C string back to a Go string.&lt;/span&gt;
    &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;C&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;GoString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;buf&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That done, we can now consume &lt;code&gt;GetExePathFromPid&lt;/code&gt; in our application.&lt;/p&gt;

&lt;p&gt;To see that in place, check out &lt;a href="https://github.com/cirocosta/pidpath"&gt;cirocosta/pidpath&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing thoughts
&lt;/h3&gt;

&lt;p&gt;It was interesting to me to check out how different things are in MacOS land.&lt;/p&gt;

&lt;p&gt;Although I use a Macbook Pro as a personal computer (and a Mac at work), I’ve not really paid attention to these little details.&lt;/p&gt;

&lt;p&gt;Also, &lt;code&gt;/proc&lt;/code&gt; is just &lt;strong&gt;so&lt;/strong&gt; valuable! Definitely worth knowing more about other functionality over there. Make sure you check out &lt;a href="https://amzn.to/2QWyXp9"&gt;The Linux Programming Interface: A Linux and UNIX System Programming Handbook&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you have any questions, or suggestions to improve this blog post, please let me know! I’m &lt;a href="https://twitter.com/cirowrc"&gt;cirowrc&lt;/a&gt;, and I’d love to chat.&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>programming</category>
      <category>go</category>
      <category>linux</category>
    </item>
    <item>
      <title>Dmesg under the hood</title>
      <dc:creator>Ciro S. Costa</dc:creator>
      <pubDate>Sat, 22 Sep 2018 00:00:00 +0000</pubDate>
      <link>https://dev.to/cirowrc/dmesg-under-the-hood-n9n</link>
      <guid>https://dev.to/cirowrc/dmesg-under-the-hood-n9n</guid>
      <description>&lt;p&gt;Hey,&lt;/p&gt;

&lt;p&gt;This week I wanted to discover a bit more about how &lt;code&gt;dmesg&lt;/code&gt; works under the hood. In the past, I wanted to have alerting based on error messages popping at &lt;code&gt;dmesg&lt;/code&gt;, so, maybe by trying to create something that uses the same thing that &lt;code&gt;dmesg&lt;/code&gt; uses under the hood, I could better understand it.&lt;/p&gt;

&lt;p&gt;Also, I knew that in some systems, it was possible to gather the same information from &lt;code&gt;kern.log&lt;/code&gt; and that &lt;code&gt;dmesg&lt;/code&gt; was all about reading “the kernel ring buffer”, but, what did that mean?&lt;/p&gt;

&lt;p&gt;More specifically, where was &lt;code&gt;dmesg&lt;/code&gt; reading from?&lt;/p&gt;

&lt;p&gt;In this blog post, I go through some exploration to better understand the whole picture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Producing logs from kernel space&lt;/li&gt;
&lt;li&gt;Producing logs from iptables&lt;/li&gt;
&lt;li&gt;Producing logs from a Linux loadable kernel module&lt;/li&gt;
&lt;li&gt;Producing logs from kmsg&lt;/li&gt;
&lt;li&gt;Seeing kernel logs from user space&lt;/li&gt;
&lt;li&gt;Interpreting the kmsg messages&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;If you have any questions, drop me a message &lt;a href="https://twitter.com/cirowrc"&gt;@cirowrc&lt;/a&gt; on Twitter!&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Producing logs from kernel space
&lt;/h3&gt;

&lt;p&gt;Whenever something in the Linux kernel (which could be a &lt;a href="https://en.wikipedia.org/wiki/Loadable_kernel_module"&gt;module&lt;/a&gt;) wants to do the equivalent of a &lt;a href="https://linux.die.net/man/3/printf"&gt;&lt;code&gt;printf&lt;/code&gt;&lt;/a&gt;, a similar utility (&lt;code&gt;printk&lt;/code&gt;) can be used.&lt;/p&gt;

&lt;p&gt;That allows the program to give information back to the developer (or any other user) in userspace to know more about what’s going on with the module - be a warning message, stack traces or some pure debugging information.&lt;/p&gt;

&lt;p&gt;To test out producing logs from the Kernel, I came up with some ideas:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;a href="https://linux.die.net/man/8/iptables"&gt;&lt;code&gt;iptables&lt;/code&gt;&lt;/a&gt; has a &lt;a href="http://ipset.netfilter.org/iptables-extensions.man.html#lbDD"&gt;&lt;code&gt;LOG&lt;/code&gt; target&lt;/a&gt; that essentially produces some logs from &lt;code&gt;iptables&lt;/code&gt; itself whenever the target is, well, targetted. Being &lt;code&gt;iptables&lt;/code&gt; something that runs in kernel space (not the &lt;code&gt;cli&lt;/code&gt;, I mean - the actual thing), we could see logs coming out of the kernel;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;writing a minimal kernel module should not be something very hard - many people did that before. I could write a &lt;code&gt;printk("hello-world")&lt;/code&gt; and that’s it!&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;check if there’s something simpler that we could use to produce the logs (maybe the Kernel exposes a standard interface for doing that?)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Being this an exploration, why not try all of them?&lt;/p&gt;

&lt;h3&gt;
  
  
  Producing logs from iptables
&lt;/h3&gt;

&lt;p&gt;Although this blog post is not particularly about iptables, we can use it as an example where interacting with something that is going on under the hood deep in the kernel is interesting for a user that sits on userspace.&lt;/p&gt;

&lt;p&gt;From &lt;a href="https://linux.die.net/man/8/iptables"&gt;&lt;code&gt;iptables&lt;/code&gt; man page&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Iptables is used to set up, maintain, and inspect the tables of IP packet filter rules in the Linux kernel. Several different tables may be defined.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;These mentioned rules can be either very simple things (drop a packet if it comes from a given source), or some very complicated chain of rules that depend on a bunch of conditionals.&lt;/p&gt;

&lt;p&gt;Acknowledging that it’s very useful to be able to visualize the packets that are hitting a specific chain of rules, the &lt;code&gt;LOG&lt;/code&gt; target came to existence.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;LOG: Turn on kernel logging of matching packets.&lt;/p&gt;

&lt;p&gt;When this option is set for a rule, the Linux kernel will print some information on all matching packets (like most IP/IPv6 header fields) via the kernel log.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here’s an example set up that allows us to see that working:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# List the current state of the `filter` table.&lt;/span&gt;
&lt;span class="c"&gt;# As we can see below, nothing is set up:&lt;/span&gt;
&lt;span class="c"&gt;# - any packet arriving w/ our machine as the&lt;/span&gt;
&lt;span class="c"&gt;# destination is accepted;&lt;/span&gt;
&lt;span class="c"&gt;# - any packet arriving that should be forwarded&lt;/span&gt;
&lt;span class="c"&gt;# is dropped;&lt;/span&gt;
&lt;span class="c"&gt;# - any packet that is sent from our machine is&lt;/span&gt;
&lt;span class="c"&gt;# accepted (can go through).&lt;/span&gt;
iptables &lt;span class="nt"&gt;--table&lt;/span&gt; filter &lt;span class="nt"&gt;--list&lt;/span&gt;
Chain INPUT &lt;span class="o"&gt;(&lt;/span&gt;policy ACCEPT&lt;span class="o"&gt;)&lt;/span&gt;
target prot opt &lt;span class="nb"&gt;source &lt;/span&gt;destination

Chain FORWARD &lt;span class="o"&gt;(&lt;/span&gt;policy DROP&lt;span class="o"&gt;)&lt;/span&gt;
target prot opt &lt;span class="nb"&gt;source &lt;/span&gt;destination

Chain OUTPUT &lt;span class="o"&gt;(&lt;/span&gt;policy ACCEPT&lt;span class="o"&gt;)&lt;/span&gt;
target prot opt &lt;span class="nb"&gt;source &lt;/span&gt;destination

&lt;span class="c"&gt;# Add a rule to the OUTPUT chain to log every packet&lt;/span&gt;
&lt;span class="c"&gt;# that is destined towards 8.8.8.8 (google's public&lt;/span&gt;
&lt;span class="c"&gt;# dns) &lt;/span&gt;
iptables &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--table&lt;/span&gt; filter &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--insert&lt;/span&gt; OUTPUT &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--jump&lt;/span&gt; LOG &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--destination&lt;/span&gt; 8.8.8.8 &lt;span class="se"&gt;\&lt;/span&gt;
        &lt;span class="nt"&gt;--log-prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"[google-dns-out]"&lt;/span&gt;

&lt;span class="c"&gt;# Check that the rule has been placed in the OUTPUT &lt;/span&gt;
&lt;span class="c"&gt;# chain of the `filter` table&lt;/span&gt;
iptables &lt;span class="nt"&gt;--table&lt;/span&gt; filter &lt;span class="nt"&gt;--list&lt;/span&gt; OUTPUT &lt;span class="nt"&gt;--numeric&lt;/span&gt;
Chain OUTPUT &lt;span class="o"&gt;(&lt;/span&gt;policy ACCEPT&lt;span class="o"&gt;)&lt;/span&gt;
target prot opt &lt;span class="nb"&gt;source &lt;/span&gt;destination
LOG all &lt;span class="nt"&gt;--&lt;/span&gt; 0.0.0.0/0 8.8.8.8 LOG flags 0 level 4 prefix &lt;span class="s2"&gt;"[google-dns-out]"&lt;/span&gt;

&lt;span class="c"&gt;# Perform a DNS query targetting 8.8.8.8&lt;/span&gt;
dig example.com @8.8.8.8
... example.com. 18272  IN  A   93.184.216.34

&lt;span class="c"&gt;# Verify the request packet in our logs (dmesg)&lt;/span&gt;
dmesg | &lt;span class="nb"&gt;grep &lt;/span&gt;google-dns-out
&lt;span class="o"&gt;[&lt;/span&gt;66458.608136] &lt;span class="o"&gt;[&lt;/span&gt;google-dns-out]IN&lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;OUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;enp0s3 &lt;span class="nv"&gt;SRC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;10.0.2.15 &lt;span class="nv"&gt;DST&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;8.8.8.8 &lt;span class="nv"&gt;LEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;80 &lt;span class="nv"&gt;TOS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00 &lt;span class="nv"&gt;PREC&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;0x00 &lt;span class="nv"&gt;TTL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;64 &lt;span class="nv"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;30602 &lt;span class="nv"&gt;PROTO&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;UDP &lt;span class="nv"&gt;SPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;39573 &lt;span class="nv"&gt;DPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;53 &lt;span class="nv"&gt;LEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;60
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Producing logs from a Linux loadable kernel module
&lt;/h3&gt;

&lt;p&gt;Not being a driver developer myself (honestly, having never written a kernel module before), it was interesting to look for resources that would teach me how to accomplish this task.&lt;/p&gt;

&lt;p&gt;Based on &lt;a href="https://linux-kernel-labs.github.io/master/labs/kernel_modules.html"&gt;a guide from The Linux Kernel Labs&lt;/a&gt;, I came up with the following code for a very simple kernel module:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight c"&gt;&lt;code&gt;&lt;span class="cm"&gt;/**
 * `module.h` contains the most basic functionality needed for
 * us to create a loadable kernel module, including the `MODULE_*`
 * macros, `module_*` functions and including a bunch of other
 * relevant headers that provide useful functionality for us
 * (for instance, `printk`, which comes from `linux/printk.h`,
 * a header included by `linux/module.h`).
 */&lt;/span&gt;

&lt;span class="cp"&gt;#include &amp;lt;linux/module.h&amp;gt;
&lt;/span&gt;
&lt;span class="cm"&gt;/**
 * Following, we make use of several macros to properly provide
 * information about the kernel module that we're creating.
 *
 * The information supplied here are visible through tools like
 * `modinfo`.
 *
 * Note.: the license you choose here **DOES AFFECT** other things -
 * by using a proprietary license your kernel will be "tainted".
 */&lt;/span&gt;
&lt;span class="n"&gt;MODULE_LICENSE&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"GPL"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_AUTHOR&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Ciro S. Costa"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_DESCRIPTION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"A hello-world printer"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;MODULE_VERSION&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"0.1"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="cm"&gt;/** hello_init - initializes the module
 *
 * The `hello_init` method defines the procedures that performs the set up
 * of our module.
 */&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;int&lt;/span&gt;
&lt;span class="nf"&gt;hello_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
         &lt;span class="c1"&gt;// By making use of `printk` here (in the initialization),&lt;/span&gt;
         &lt;span class="c1"&gt;// we can look at `dmesg` and verify that what we log here&lt;/span&gt;
         &lt;span class="c1"&gt;// appears there at the moment that we load the module with&lt;/span&gt;
         &lt;span class="c1"&gt;// `insmod`.&lt;/span&gt;
    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KERN_INFO&lt;/span&gt; &lt;span class="s"&gt;"HELLO-WORLD: Hello world!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&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="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;hello_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// similar to `init`, but for the removal time.&lt;/span&gt;
    &lt;span class="n"&gt;printk&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;KERN_INFO&lt;/span&gt; &lt;span class="s"&gt;"HELLO-WORLD: Bye bye world!&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&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;// registers the `hello_init` method as the method to run at module&lt;/span&gt;
&lt;span class="c1"&gt;// insertion time.&lt;/span&gt;
&lt;span class="n"&gt;module_init&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_init&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// similar, but for `removal`&lt;/span&gt;
&lt;span class="n"&gt;module_exit&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;hello_exit&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;em&gt;ps.: the source code is available at &lt;a href="https://github.com/cirocosta/hello-world-lkm"&gt;github.com/cirocosta/hello-world-lkm&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Load the module, and there you go:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dmesg | &lt;span class="nb"&gt;grep &lt;/span&gt;HELLO-WORLD
&lt;span class="o"&gt;[&lt;/span&gt;62076.224353] HELLO-WORLD: Hello world!
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Producing logs from kmsg
&lt;/h3&gt;

&lt;p&gt;A standard interface that we can use to insert messages into the &lt;code&gt;printk&lt;/code&gt; buffer is exactly the same that we can use to read the messages from it: &lt;code&gt;/dev/kmsg&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;From the &lt;a href="https://www.kernel.org/doc/Documentation/ABI/testing/dev-kmsg"&gt;kernel documentation&lt;/a&gt;:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Injecting messages: Every write() to the opened device node places a log entry in the kernel’s printk buffer.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;That is, whatever we &lt;code&gt;echo "haha"&lt;/code&gt; as a single &lt;code&gt;write&lt;/code&gt; to &lt;code&gt;/dev/kmsg&lt;/code&gt; goes into the buffer.&lt;/p&gt;

&lt;p&gt;Let’s try it then:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Generate the message from my current unprivileged&lt;/span&gt;
&lt;span class="c"&gt;# user and then pipe to the privileged `tee` which is&lt;/span&gt;
&lt;span class="c"&gt;# able to write into `/dev/kmsg` (yep, /dev/kmsg can be&lt;/span&gt;
&lt;span class="c"&gt;# see and read, but to write you need more privileges)&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"haha"&lt;/span&gt; | &lt;span class="nb"&gt;sudo tee&lt;/span&gt; &lt;span class="s2"&gt;"/dev/kmsg"&lt;/span&gt;

&lt;span class="c"&gt;# Check that we can see our message is indeed there:&lt;/span&gt;
dmesg | &lt;span class="nb"&gt;grep &lt;/span&gt;haha
&lt;span class="o"&gt;[&lt;/span&gt;67030.010334] haha
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Seeing kernel logs from user space
&lt;/h3&gt;

&lt;p&gt;Having already spoiled the blog post by mentioning &lt;code&gt;kmsg&lt;/code&gt; in the section before, there’s not a bunch to talk now.&lt;/p&gt;

&lt;p&gt;The kernel provides to us &lt;code&gt;/dev/kmsg&lt;/code&gt; in userspace, a special device that allows us to read from the ring buffer (with multitenancy in mind), and that’s what dmesg uses.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Trace the syscalls `openat` and `read` to verify&lt;/span&gt;
&lt;span class="c"&gt;# that it reads from `/dev/kmsg`&lt;/span&gt;
strace &lt;span class="nt"&gt;-e&lt;/span&gt; openat,read &lt;span class="nt"&gt;-f&lt;/span&gt; dmesg &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/null
openat&lt;span class="o"&gt;(&lt;/span&gt;AT_FDCWD, &lt;span class="s2"&gt;"/dev/kmsg"&lt;/span&gt;, O_RDONLY|O_NONBLOCK&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 3
&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;3, &lt;span class="s2"&gt;"5,0,0,-;Linux version 4.15.0-34-"&lt;/span&gt;..., 8191&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 192
&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;3, &lt;span class="s2"&gt;"6,1,0,-;Command line: BOOT_IMAGE"&lt;/span&gt;..., 8191&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 142
&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;3, &lt;span class="s2"&gt;"6,2,0,-;KERNEL supported cpus:&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;, 8191&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 31
&lt;span class="nb"&gt;read&lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;3, &lt;span class="s2"&gt;"6,3,0,-; Intel GenuineIntel&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;, 8191&lt;span class="o"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; 29
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Going even deeper, whenever a &lt;code&gt;read(2)&lt;/code&gt; syscall is emitted targetting such file, the kernel triggers &lt;a href="https://elixir.bootlin.com/linux/v4.18.8/source/kernel/printk/printk.c#L823"&gt;&lt;code&gt;kernel/printk/devkmsg_read&lt;/code&gt;&lt;/a&gt; internally, taking a message from the circular queue, formatting it and then sending back to the user.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# We can use `iovisor/bcc#examples/trace/stacknoop.py` to&lt;/span&gt;
&lt;span class="c"&gt;# gather the stack trace from the execution of `devkmsg_read`&lt;/span&gt;
&lt;span class="c"&gt;# to verify that the `read` gets right there when `vfs_read`&lt;/span&gt;
&lt;span class="c"&gt;# is called.&lt;/span&gt;
./stacksnoop.py &lt;span class="nt"&gt;-v&lt;/span&gt; devkmsg_read
TIME&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; COMM PID CPU FUNCTION
1.875072956 &lt;span class="nb"&gt;tail &lt;/span&gt;1565 0 devkmsg_read
    devkmsg_read
    vfs_read
    sys_read
    do_syscall_64
    entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A similar path is followed when writing to the circular queue as well: whenever a &lt;code&gt;write(2)&lt;/code&gt; is issued, at some point &lt;a href="https://elixir.bootlin.com/linux/v4.18.8/source/kernel/printk/printk.c#L760"&gt;&lt;code&gt;devkmsg_write&lt;/code&gt;&lt;/a&gt; is called.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;devkmsg&lt;/code&gt; translates such call to the equivalent of a &lt;code&gt;printk&lt;/code&gt;, which then takes the path of reaching &lt;code&gt;log_store&lt;/code&gt;, the method that ends up finally taking a free space from the queue and adding the log message:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# In one terminal&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"haha"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; /dev/kmsg

&lt;span class="c"&gt;# In another terminal&lt;/span&gt;
./stacksnoop.py &lt;span class="nt"&gt;-v&lt;/span&gt; log_store
TIME&lt;span class="o"&gt;(&lt;/span&gt;s&lt;span class="o"&gt;)&lt;/span&gt; COMM PID CPU FUNCTION
1.786375046 bash 1450 2 log_store
    log_store
    printk_emit
    devkmsg_write
    new_sync_write
    __vfs_write
    vfs_write
    sys_write
    do_syscall_64
    entry_SYSCALL_64_after_hwframe
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By knowing that the kernel provides this interface, we can implement a simple program that constantly performs &lt;code&gt;read(2)&lt;/code&gt;s against such device and then parses the contents (messages) that arrive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Interpreting the kmsg messages
&lt;/h3&gt;

&lt;p&gt;Knowing that every &lt;code&gt;read(2)&lt;/code&gt; syscall performed against &lt;code&gt;/dev/kmsg&lt;/code&gt; returns us a single message, we’re left to: - implementing a reader that continuously looks at &lt;code&gt;/dev/kmsg&lt;/code&gt; and then extracts the raw messages from there; as well as - implementing the parsing of those messages.&lt;/p&gt;

&lt;p&gt;The later is the most interesting, imo.&lt;/p&gt;

&lt;p&gt;Each message comes packed in the following format: a list of comma-separated info fields and a message (these, separated by a semicolon).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//
//                  INFO                      MSG
//     .------------------------------------------. .------.
//    |                                            |        |
//    | int int      int      char, &amp;lt;ignore&amp;gt;   | string |
//    prefix,   seq, timestamp_us,flag[,..........];&amp;lt;message&amp;gt;
//
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There are four standard fields in the info section, leaving room for other fields in the future.&lt;/p&gt;

&lt;p&gt;From the &lt;code&gt;priority&lt;/code&gt; field, we can extract two pieces of information: priority and facility.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;// DecodePrefix extracts both priority and facility from a given
// syslog(2) encoded prefix.
//
//     facility    priority
//      .-----------.  .-----.
//      |           |  |     |
//  7  6  5  4  3  2  1  0    bits
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the rest of the fields, we’re able to know when the message was produced and what ID does such message carry in the sequence of messages that have been put in the buffer.&lt;/p&gt;

&lt;p&gt;If you’re interested in seeing this parsing in the form of actual code, I wrote a Golang implementation that you can check here: &lt;a href="https://github.com/cirocosta/dmesg_exporter/blob/fc7962f46d304c158f21cc71cf2049af7d183c0a/kmsg/kmsg.go#L178"&gt;github.com/cirocosta/dmesg_exporter/kmsg/kmsg.go&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Closing thoughts
&lt;/h3&gt;

&lt;p&gt;It was great to have the opportunity of going deep into the stack and verifying how components from the kernel can communicate with userspace applications.&lt;/p&gt;

&lt;p&gt;That led me to create &lt;a href="https://github.com/cirocosta/dmesg_exporter"&gt;&lt;code&gt;dmesg_exporter&lt;/code&gt;&lt;/a&gt;, a tool for exporting “dmesg” logs metrics so that people can eventually alert messages marked as “critical” arriving from a specific facility.&lt;/p&gt;

&lt;p&gt;During the writing of this blog post, I made use of the following book: &lt;a href="https://amzn.to/2QWyXp9"&gt;The Linux Programming Interface&lt;/a&gt;. Please make sure you check it out! It’s definitely one of the best books on Linux out there.&lt;/p&gt;

&lt;p&gt;If you’ve had any questions, or have ideas for improvements, please let me know! I’m &lt;a href="https://twitter.com/cirowrc"&gt;cirowrc&lt;/a&gt; on Twitter, and I’d love to hear from you!&lt;/p&gt;

&lt;p&gt;Have a good one!&lt;/p&gt;

</description>
      <category>linux</category>
      <category>devops</category>
    </item>
  </channel>
</rss>
