title: Portable way to detect different kinds of network error
body: <p>I would like to identify what kind of error occurred in the network level. The only way I found was checking the error messages with a regular expression, but now I discovered that this messages can be in different languages (depending on the OS configuration), making it difficult to detect by regular expressions. Is there a better way to do it?</p>
  
  <pre><code>package main
  
  import (
    "github.com/miekg/dns"
    "net"
    "regexp"
  )
  
  func main() {
    var c dns.Client
    m := new(dns.Msg)
  
    m.SetQuestion("3com.br.", dns.TypeSOA)
    _, _, err := c.Exchange(m, "ns1.3com.com.:53")
    checkErr(err)
  
    m.SetQuestion("example.com.", dns.TypeSOA)
    _, _, err = c.Exchange(m, "idontexist.br.:53")
    checkErr(err)
  
    m.SetQuestion("acasadocartaocuritiba.blog.br.", dns.TypeSOA)
    _, _, err = c.Exchange(m, "ns7.storedns22.in.:53")
    checkErr(err)
  }
  
  func checkErr(err error) {
    if err == nil {
      println("Ok")
    } else if netErr, ok := err.(net.Error); ok &amp;&amp; netErr.Timeout() {
      println("Timeout")
    } else if match, _ := regexp.MatchString(".*lookup.*", err.Error()); match {
      println("Unknown host")
    } else if match, _ := regexp.MatchString(".*connection refused.*", err.Error()); match {
      println("Connection refused")
    } else {
      println("Other error")
    }
  }
  </code></pre>
  
  <p>Result:</p>
  
  <pre><code>$ go run neterrors.go
  Timeout
  Unknown host
  Connection refused
  </code></pre>
  
  <p>I discover the problem when testing the system in a Windows OS with Portuguese as default language.</p>
  
  <p><strong>[EDIT]</strong></p>
  
  <p>I found a way to do it using the OpError. Here is the checkErr function again with the new approach. If someone has a better solution I will be very glad to known it!</p>
  
  <pre><code>func checkErr(err error) {
    if err == nil {
      println("Ok")
    } else if netErr, ok := err.(net.Error); ok &amp;&amp; netErr.Timeout() {
      println("Timeout")
    } else if opError, ok := err.(*net.OpError); ok {
      if opError.Op == "dial" {
        println("Unknown host")
      } else if opError.Op == "read" {
        println("Connection refused")
      }
    }
  }
  </code></pre>
  
  <p><strong>[EDIT2]</strong></p>
  
  <p>Updated after seong answer.</p>
  
  <pre><code>func checkErr(err error) {
    if err == nil {
      println("Ok")
      return
  
    } else if netError, ok := err.(net.Error); ok &amp;&amp; netError.Timeout() {
      println("Timeout")
      return
    }
  
    switch t := err.(type) {
    case *net.OpError:
      if t.Op == "dial" {
        println("Unknown host")
      } else if t.Op == "read" {
        println("Connection refused")
      }
  
    case syscall.Errno:
      if t == syscall.ECONNREFUSED {
        println("Connection refused")
      }
    }
  }
  </code></pre>