今天让我们一起来看看UDP端口探测是怎么个事,本篇文章主要用到SOCK_DGRAM 套接字类型。
socket套接字相关的文章:
SOCK_DGRAM 是 Linux 套接字(Socket)的一种类型,它提供无连接的、不可靠的数据报服务。这种套接字通常用于 UDP (User Datagram Protocol) 用户数据报协议。
UDP报文结构

特性
- 无连接:通信前不需要建立连接
- 数据报服务:数据以独立的数据包形式传输
- 不可靠传输:不保证数据到达顺序,可能丢失或重复
- 边界保留:数据保持发送时的消息边界
- 高效:相比 SOCK_STREAM 开销更小
示例:向目标服务发送UDP报文,测试目标服务是否回包(验证端口是否存活)
func main() {
// 创建套接字
fd, err := syscall.Socket(
syscall.AF_INET,
syscall.SOCK_DGRAM,
syscall.IPPROTO_UDP,
)
if err != nil {
log.Fatalf("create socket err: %v", err)
}
defer syscall.Close(fd)
// 设置超时
tv := syscall.Timeval{Sec: 3, Usec: 0}
if err := syscall.SetsockoptTimeval(
fd, syscall.SOL_SOCKET, syscall.SO_RCVTIMEO, &tv); err != nil {
log.Fatalf("Set timeout error: %v\n", err)
return
}
// 构造目标IP及端口
dstIP := net.ParseIP("192.168.1.5").To4()
dstPort := 1234
dstAddr := &syscall.SockaddrInet4{Port: dstPort}
copy(dstAddr.Addr[:], dstIP.To4())
// 发送探测数据
msg := []byte("hello udp!")
if err := syscall.Sendto(fd, msg, 0, dstAddr); err != nil {
log.Fatalf("send err: %v", err)
return
}
// 尝试接收响应
buf := make([]byte, 1024)
_, _, err = syscall.Recvfrom(fd, buf, 0)
if err != nil {
if err == syscall.EAGAIN || err == syscall.EWOULDBLOCK {
log.Fatalf("No response received\n")
} else {
log.Fatalf("Receive error: %v\n", err)
}
return
}
log.Fatalf("udp probe success!\n")
}
(1)首先创建syscall.Socket()套接字,指定syscall.SOCK_DGRAM套接字类型
(2)设置链接超时时间
(3)创建要探测的UDP服务地址(目标IP及端口)
(4)封装消息体
(5)最后使用 syscall.Recvfrom 接收UDP服务响应
📢 注意
由于UDP协议是非面向连接的,对UDP端口的探测也就不可能像TCP端口的探测那样依赖于连接建立过程,这也使得UDP端口扫描的可靠性不高。
上述案例是建立在目标udp服务有回包的基础上实现的,如果目标udp服务没有回包我们如何来探测呢❓
对UDP端口的扫描,参考另一种思路:利用ICMP端口不可达报文进行扫描。
原理是当一个UDP端口接收到一个UDP数据报时:
- 如果它是关闭的,就会给源端发回一个
ICMP端口不可达数据报; - 如果它是开放的,那么就会忽略这个数据报,也就是将它丢弃而不返回任何的信息。
下面用nmap命令针对 114 DNS服务UDP端口开始扫描

扫描状态显示 open|filterd 代表可能丢弃 UDP 包,导致结果不确定性。
下面通过tcpdump开始抓包
① 首先namp首先发送了ICMP包探测
② 随后114DNS服务进行ICMP回包
③ ④ icmp应答后,nmap才开始发UDP数据包,最后114DNS也没有回复udp数据包。


1万+

被折叠的 条评论
为什么被折叠?



