Skip to content

Commit 7f52a61

Browse files
committed
Add propper udp.
1 parent a844777 commit 7f52a61

File tree

2 files changed

+178
-36
lines changed

2 files changed

+178
-36
lines changed

methods/udp.go

Lines changed: 170 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,208 @@
11
package methods
22

33
import (
4+
"context"
45
"fmt"
56
"net"
67
"strconv"
8+
"strings"
79
"time"
810

911
"github.com/Bastih18/NoPing/globals"
10-
1112
ps "github.com/Bastih18/NoPing/printStats"
12-
1313
"github.com/fatih/color"
1414
)
1515

16-
func UDPPing(host string, port int, count int, timeout time.Duration) {
17-
address := net.JoinHostPort(host, fmt.Sprintf("%d", port))
18-
conn, err := net.DialTimeout("udp", address, timeout)
16+
// Define a list of protocols and their corresponding ports and packet formats
17+
var udpMessages = []struct {
18+
Protocol string
19+
Port int
20+
Packet []byte
21+
}{
22+
{"dns", 53, []byte{
23+
0xaa, 0xbb, // Transaction ID
24+
0x01, 0x00, // Standard query
25+
0x00, 0x01, // One question
26+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
27+
0x03, 'w', 'w', 'w',
28+
0x06, 'g', 'o', 'o', 'g', 'l', 'e',
29+
0x03, 'c', 'o', 'm', 0x00, // "www.google.com"
30+
0x00, 0x01, // Type A query
31+
0x00, 0x01, // Class IN (Internet)
32+
}},
33+
{"ntp", 123, []byte{
34+
0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
35+
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
36+
}},
37+
{"snmp", 161, []byte{
38+
0x30, 0x26, 0x02, 0x01, 0x00, 0x04, 0x14, 0x2b, 0x06, 0x01,
39+
0x04, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
40+
}},
41+
{"upnp", 1900, []byte{
42+
0x00, 0x00, 0x00, 0x00, // Example SSDP request for UPnP
43+
}},
44+
{"steam", 27030, []byte{
45+
0xFF, 0xFF, 0xFF, 0xFF, // Magic prefix for Steam query
46+
0x11, // Steam query request type
47+
0x00, 0x00, 0x00, 0x00, // Empty header
48+
}},
49+
{"syslog", 514, []byte{
50+
0x3c, 0x01, // Header
51+
0x00, 0x00, // Facility and Severity
52+
0x00, 0x00, 0x00, 0x00, // Time and Hostname
53+
0x00, 0x00, 0x00, 0x00, // AppName and Message
54+
}},
55+
{"tftp", 69, []byte{
56+
0x00, 0x01, // Request Packet
57+
0x00, 0x00, 0x00, 0x01, // Request to read file
58+
}},
59+
{"radius", 1812, []byte{
60+
0x01, 0x00, 0x00, 0x06, // Request type
61+
0x00, 0x00, 0x00, 0x01, // Identifier and length
62+
// More RADIUS-specific fields...
63+
}},
64+
{"chargen", 19, []byte{0x00}}, // Simple message
65+
{"nfs", 2049, []byte{
66+
0x00, 0x00, 0x00, 0x00, // NFS request packet
67+
}},
68+
{"sip", 5060, []byte{
69+
0x00, 0x01, 0x00, 0x00, // Request for SIP service
70+
// Further SIP message fields...
71+
}},
72+
{"dhcp", 67, []byte{
73+
0x01, 0x01, 0x06, 0x00, // DHCP Discover
74+
0x00, 0x00, 0x00, 0x00, // Client hardware address
75+
// Further DHCP fields...
76+
}},
77+
{"bgp", 179, []byte{
78+
0x00, 0x01, 0x00, 0x00, // Open message fields
79+
}},
80+
}
1981

20-
greenBold := color.New(color.Bold, color.FgGreen)
21-
redBold := color.New(color.Bold, color.FgRed)
82+
// Auto-detect protocol based on port
83+
func autoDetectProtocol(port int) string {
84+
for _, entry := range udpMessages {
85+
if entry.Port == port {
86+
return entry.Protocol
87+
}
88+
}
89+
return "" // Unknown protocol for the given port
90+
}
2291

92+
// Generalized function to send UDP packets based on protocol
93+
func UDPPing(host string, port int, timeout time.Duration, protocol string, count int) {
94+
// If protocol is "auto", detect it based on the port
95+
if protocol == "auto" {
96+
protocol = autoDetectProtocol(port)
97+
if protocol == "" {
98+
fmt.Printf("❌ Unknown protocol for port %d\n", port)
99+
return
100+
}
101+
}
102+
103+
// Convert protocol to lowercase to ensure consistency
104+
protocol = strings.ToLower(protocol)
105+
106+
// Find the matching protocol in the udpMessages list
107+
var packet []byte
108+
for _, entry := range udpMessages {
109+
if entry.Protocol == protocol {
110+
packet = entry.Packet
111+
break
112+
}
113+
}
114+
115+
// Check if the protocol is valid
116+
if packet == nil {
117+
fmt.Printf("❌ Unknown protocol: %s\n", protocol)
118+
return
119+
}
120+
121+
address := net.JoinHostPort(host, fmt.Sprintf("%d", port))
122+
udpAddr, err := net.ResolveUDPAddr("udp", address)
23123
if err != nil {
24-
fmt.Printf("%s\n", redBold.Sprintf("Error dialing UDP: %v", err))
124+
fmt.Printf("Error resolving UDP address: %v\n", err)
25125
return
26126
}
27-
defer conn.Close()
28127

128+
// Colorized outputs
129+
greenBold := color.New(color.Bold, color.FgGreen)
130+
redBold := color.New(color.Bold, color.FgRed)
131+
132+
// Stats tracking
29133
stats := globals.Stats{}
30134

135+
// Loop to send multiple pings
31136
for i := 0; i < count; i++ {
32137
if globals.Stop {
33138
break
34139
}
35-
36140
stats.Attempted++
37-
message := []byte("ping")
38141
start := time.Now()
39142

40-
_, err = conn.Write(message)
41-
if err != nil {
42-
stats.Failed++
43-
fmt.Printf("%s\n", redBold.Sprint("❌ Connection timed out"))
44-
time.Sleep(time.Second)
45-
continue
46-
}
143+
// Timeout context for this UDP request
144+
ctx, cancel := context.WithTimeout(context.Background(), timeout)
145+
go func() {
146+
select {
147+
case <-globals.StopChan:
148+
cancel()
149+
break
150+
case <-ctx.Done():
151+
}
152+
}()
47153

48-
conn.SetReadDeadline(time.Now().Add(timeout))
49-
buffer := make([]byte, 1024)
50-
_, err = conn.Read(buffer)
154+
// Bind to a local address
155+
localAddr, _ := net.ResolveUDPAddr("udp", "0.0.0.0:0")
156+
conn, err := net.DialUDP("udp", localAddr, udpAddr)
51157
elapsed := time.Since(start)
158+
defer cancel()
52159

160+
// Check if the connection was successful
53161
if err != nil {
54162
stats.Failed++
55-
fmt.Printf("❌ UDP ping to %s: timeout: %v\n", redBold.Sprint(address), redBold.Sprint(err))
163+
fmt.Printf("%s\n", redBold.Sprint("❌ Connection timed out"))
56164
} else {
57-
stats.Connected++
58-
stats.TotalTime += elapsed
59-
60-
if stats.Connected == 1 || elapsed < stats.Min {
61-
stats.Min = elapsed
62-
}
63-
if elapsed > stats.Max {
64-
stats.Max = elapsed
165+
// Send the query packet
166+
_, err = conn.Write(packet)
167+
if err != nil {
168+
stats.Failed++
169+
fmt.Printf("%s\n", redBold.Sprint("❌ Failed to send UDP packet"))
170+
continue
65171
}
66172

67-
fmt.Printf("✅ Connected to %s: time=%s protocol=%s port=%s\n",
68-
greenBold.Sprint(host),
69-
greenBold.Sprintf("%.3fms", float64(elapsed.Nanoseconds())/1e6),
70-
greenBold.Sprint("UDP"),
71-
greenBold.Sprint(strconv.Itoa(port)))
173+
// Set read deadline for response
174+
conn.SetReadDeadline(time.Now().Add(timeout))
175+
buffer := make([]byte, 1024)
176+
n, _, err := conn.ReadFrom(buffer)
177+
178+
// If we received any data, it's valid and the service is online
179+
if err == nil && n > 0 {
180+
stats.Connected++
181+
stats.TotalTime += elapsed
182+
183+
// Track min/max times
184+
if stats.Connected == 1 || elapsed < stats.Min {
185+
stats.Min = elapsed
186+
}
187+
if elapsed > stats.Max {
188+
stats.Max = elapsed
189+
}
190+
191+
// Convert time to milliseconds for correct output
192+
fmt.Printf("✅ UDP ping to %s: time=%.3fms protocol=%s port=%s\n",
193+
greenBold.Sprint(host),
194+
float64(elapsed.Nanoseconds())/1e6, // Convert nanoseconds to milliseconds
195+
greenBold.Sprint(protocol),
196+
greenBold.Sprint(strconv.Itoa(port)),
197+
)
198+
} else {
199+
// If no response is received but the connection succeeded, treat it as "open"
200+
stats.Connected++
201+
fmt.Printf("✅ UDP ping to %s: port open but no response received\n", greenBold.Sprint(address))
202+
}
72203
}
204+
205+
// Wait before sending the next packet
73206
if i < count-1 {
74207
select {
75208
case <-time.After(time.Second):
@@ -78,5 +211,7 @@ func UDPPing(host string, port int, count int, timeout time.Duration) {
78211
}
79212
}
80213
}
214+
215+
// Print statistics after the loop
81216
ps.PrintStats("UDP", host, port, stats)
82217
}

noping.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ func main() {
4747
timeout := 1000
4848
minimal := false
4949
protocol := "tcp"
50+
packet := "auto"
5051

5152
args := os.Args[1:]
5253
for i, arg := range args {
@@ -108,6 +109,12 @@ func main() {
108109
fmt.Printf("❌ You must specify a protocol when using the %s argument\n", arg)
109110
os.Exit(0)
110111
}
112+
case "-pa", "--packet":
113+
if i+1 < len(args) && args[i+1][0] != '-' {
114+
packet = args[i+1]
115+
} else {
116+
fmt.Printf("❌ You must specify a packet when using the %s argument\n", arg)
117+
}
111118
case "-v", "--version":
112119
fmt.Println(headerText)
113120
fmt.Println("")
@@ -152,6 +159,6 @@ func main() {
152159
} else if protocol == "tcp" {
153160
methods.TCPPing(rawIp.String(), port, count, time.Duration(timeout)*time.Millisecond)
154161
} else if protocol == "udp" {
155-
methods.UDPPing(rawIp.String(), port, count, time.Duration(timeout)*time.Millisecond)
162+
methods.UDPPing(rawIp.String(), port, time.Duration(timeout)*time.Millisecond, packet, count)
156163
}
157164
}

0 commit comments

Comments
 (0)