如何区分关闭的和过滤的远程端口

I am setting up port scanner for remote server in my application using Go. I am using DialTimeout function in Go net package to check whether a remote host port is opened or not. The result is fine with success case. But, if i/o timeout happens, I need to identify whether

  1. The port is closed (No service is running) or
  2. Port is blocked (Firewall filtered) or
  3. Due to internet connectivity down in local system where the application is running.

Have tried nmap cli command, I can able to differentiate those failure 3 cases exactly. nmap command tried: nmap -sA -p port_number host_ip

I found a Go 3rd party libray to use nmap. But, I don't want to use nmap in my application. Are there any other alternatives in Go to exactly differentiate those 3 cases?

In the simple world

Lets assume you want to scan a Linux system.

If you get an ICMP message type 3 code 3, the firewall explicitly told you:

Hi, I am the firewall of your target host. The host is running. I hereby inform you that you (potentially amongst others) can not access this port. So now that you know you should quit your connection attempts. However, I won't tell you wether it is because there is no service running behind it (in which case my response is simply a courtesy) or because I was told to deny you access. Goodbye!

The port is closed if you do not get above answer and can not make a connection. I hence strongly advice to use context.WithTimeout to make a connection.

In the real world

However, this only applies if the admin of the target host did not change the ICMP message type to respond with - or chose just to drop any packets coming from sources which are not allowed to access the respective service. In the latter case, there is no way for you to know wether the port is closed or filtered.

All of the above only applies if we are talking of an iptables based firewall on the target system with default settings.

Now assume something which is by far more likely: A border firewall plus a local firewall. The border firewall might send other ICMP messages (or, again, simply drop your packages). Those rules apply additionally to the rules of the local firewall. So it is a misconception that you are actually scanning a host. It is more accurate to say that you scan the services reachable via a specific IP.

EDIT

Why would one send an ICMP message explicitly rejecting connection attempts?

There are various reasons to come to that decision. There is a good answer on serverfault.com