1
1
package methods
2
2
3
3
import (
4
+ "context"
4
5
"fmt"
5
6
"net"
6
7
"strconv"
8
+ "strings"
7
9
"time"
8
10
9
11
"github.com/Bastih18/NoPing/globals"
10
-
11
12
ps "github.com/Bastih18/NoPing/printStats"
12
-
13
13
"github.com/fatih/color"
14
14
)
15
15
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
+ }
19
81
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
+ }
22
91
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 )
23
123
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 )
25
125
return
26
126
}
27
- defer conn .Close ()
28
127
128
+ // Colorized outputs
129
+ greenBold := color .New (color .Bold , color .FgGreen )
130
+ redBold := color .New (color .Bold , color .FgRed )
131
+
132
+ // Stats tracking
29
133
stats := globals.Stats {}
30
134
135
+ // Loop to send multiple pings
31
136
for i := 0 ; i < count ; i ++ {
32
137
if globals .Stop {
33
138
break
34
139
}
35
-
36
140
stats .Attempted ++
37
- message := []byte ("ping" )
38
141
start := time .Now ()
39
142
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
+ }()
47
153
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 )
51
157
elapsed := time .Since (start )
158
+ defer cancel ()
52
159
160
+ // Check if the connection was successful
53
161
if err != nil {
54
162
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" ))
56
164
} 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
65
171
}
66
172
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
+ }
72
203
}
204
+
205
+ // Wait before sending the next packet
73
206
if i < count - 1 {
74
207
select {
75
208
case <- time .After (time .Second ):
@@ -78,5 +211,7 @@ func UDPPing(host string, port int, count int, timeout time.Duration) {
78
211
}
79
212
}
80
213
}
214
+
215
+ // Print statistics after the loop
81
216
ps .PrintStats ("UDP" , host , port , stats )
82
217
}
0 commit comments