-rw-r--r-- | shared-code/kICMP.cpp | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/shared-code/kICMP.cpp b/shared-code/kICMP.cpp new file mode 100644 index 0000000..09a8f94 --- a/dev/null +++ b/shared-code/kICMP.cpp | |||
@@ -0,0 +1,300 @@ | |||
1 | #include "../stdafx.h" | ||
2 | #include "kICMP.h" | ||
3 | |||
4 | CICMP::_mechanismus CICMP::m_mechanismus = CICMP::_icmpUndetermined; | ||
5 | |||
6 | BOOL CICMPDll::Initialize() | ||
7 | { | ||
8 | if(m_hICMP!=INVALID_HANDLE_VALUE || m_hICMPDLL) | ||
9 | Deinitialize(); | ||
10 | m_hICMPDLL = ::LoadLibraryEx("ICMP",NULL,0); | ||
11 | if(!m_hICMPDLL) | ||
12 | return FALSE; | ||
13 | *(FARPROC*)&m_icmpCF = ::GetProcAddress(m_hICMPDLL,"IcmpCreateFile"); | ||
14 | *(FARPROC*)&m_icmpSE = ::GetProcAddress(m_hICMPDLL,"IcmpSendEcho"); | ||
15 | *(FARPROC*)&m_icmpCH = ::GetProcAddress(m_hICMPDLL,"IcmpCloseHandle"); | ||
16 | if(!(m_icmpCF && m_icmpSE && m_icmpCH)){ | ||
17 | Deinitialize(); return FALSE; | ||
18 | } | ||
19 | m_hICMP = (*m_icmpCF)(); | ||
20 | if(m_hICMP==INVALID_HANDLE_VALUE){ | ||
21 | Deinitialize(); return FALSE; | ||
22 | } | ||
23 | TRACE0("ICMP-DLL Initialized\n"); | ||
24 | return TRUE; | ||
25 | } | ||
26 | void CICMPDll::Deinitialize() | ||
27 | { | ||
28 | if(m_hICMPDLL){ | ||
29 | if(m_hICMP!=INVALID_HANDLE_VALUE && m_icmpCH) | ||
30 | (*m_icmpCH)(m_hICMP); | ||
31 | ::FreeLibrary(m_hICMPDLL); m_hICMPDLL = NULL; | ||
32 | m_icmpCF = NULL; | ||
33 | m_icmpSE = NULL; | ||
34 | m_icmpCH = NULL; | ||
35 | } | ||
36 | m_hICMP=INVALID_HANDLE_VALUE; | ||
37 | if(m_sizeOut && m_bsOut){ | ||
38 | delete m_bsOut; | ||
39 | m_bsOut = NULL; m_sizeOut = 0; | ||
40 | } | ||
41 | if(m_sizeIn && m_bsIn){ | ||
42 | delete m_bsIn; | ||
43 | m_bsIn = NULL; m_sizeIn = 0; | ||
44 | } | ||
45 | } | ||
46 | |||
47 | LONG CICMPDll::Ping(const in_addr host,const UINT packetSize, | ||
48 | const UINT timeOut,LPINT pStatus) | ||
49 | { | ||
50 | if(!(m_hICMP && m_hICMPDLL && m_icmpSE)){ | ||
51 | if(pStatus) | ||
52 | (*pStatus) = icmpNotInitialized; | ||
53 | return -1; | ||
54 | } | ||
55 | VERIFY(AdjustBuffers(packetSize)); | ||
56 | IPINFO ipi; | ||
57 | memset(&ipi,0,sizeof(ipi)); | ||
58 | ipi.Ttl = 30; | ||
59 | for(UINT tmp=0;tmp<packetSize;tmp++) | ||
60 | m_bsOut[tmp]=tmp&0xFF; | ||
61 | LPICMPECHO pRep = (LPICMPECHO)m_bsIn; | ||
62 | pRep->Status = 0xFFFFFFFFl; | ||
63 | if((*m_icmpSE)(m_hICMP,host.s_addr,m_bsOut,packetSize, | ||
64 | &ipi,pRep,m_sizeIn,timeOut)) | ||
65 | TRACE0("ICMP-SendEcho succeeded\n"); | ||
66 | else | ||
67 | TRACE0("ICMP-SendEcho failed\n"); | ||
68 | LONG lrv = -1; | ||
69 | INT rv = ipUnknown; | ||
70 | switch(pRep->Status){ | ||
71 | case IP_SUCCESS: | ||
72 | lrv = pRep->RTTime; rv = ipSuccess; | ||
73 | break; | ||
74 | case IP_BUF_TOO_SMALL: rv = ipBuffTooSmall; break; | ||
75 | case IP_DEST_NET_UNREACHABLE: rv = ipDestNetUnreachable; break; | ||
76 | case IP_DEST_HOST_UNREACHABLE: rv = ipDestHostUnreachable; break; | ||
77 | case IP_DEST_PROT_UNREACHABLE: rv = ipDestProtUnreachable; break; | ||
78 | case IP_DEST_PORT_UNREACHABLE: rv = ipDestPortUnreachable; break; | ||
79 | case IP_NO_RESOURCES: rv = ipNoResources; break; | ||
80 | case IP_BAD_OPTION: rv = ipBadOption; break; | ||
81 | case IP_HW_ERROR: rv = ipHWError; break; | ||
82 | case IP_PACKET_TOO_BIG: rv = ipPacketTooBig; break; | ||
83 | case IP_REQ_TIMED_OUT: rv = ipTimeOut; break; | ||
84 | case IP_BAD_REQ: rv = ipBadRequest; break; | ||
85 | case IP_BAD_ROUTE: rv = ipBadRoute; break; | ||
86 | case IP_TTL_EXPIRED_TRANSIT: rv = ipTTLExpiredInTransit; break; | ||
87 | case IP_TTL_EXPIRED_REASSEM: rv = ipTTLExpiredInReasm; break; | ||
88 | case IP_PARAM_PROBLEM: rv = ipParamProblem; break; | ||
89 | case IP_SOURCE_QUENCH: rv = ipSourceQuench; break; | ||
90 | case IP_OPTION_TOO_BIG: rv = ipOptionTooBig; break; | ||
91 | case IP_BAD_DESTINATION: rv = ipBadDest; break; | ||
92 | } | ||
93 | if(pStatus) | ||
94 | (*pStatus)=rv; | ||
95 | return lrv; | ||
96 | } | ||
97 | |||
98 | BOOL CICMPDll::AdjustBuffers(UINT packetSize) | ||
99 | { | ||
100 | if(!packetSize) | ||
101 | packetSize=1; | ||
102 | if(packetSize>m_sizeOut){ | ||
103 | if(m_sizeOut && m_bsOut) | ||
104 | delete m_bsOut; | ||
105 | m_bsOut = new BYTE[m_sizeOut=packetSize]; | ||
106 | if(!m_bsOut) | ||
107 | return FALSE; | ||
108 | } | ||
109 | UINT sin = sizeof(ICMPECHO)+SIZE_ICMP_HDR+packetSize; | ||
110 | if(sin>m_sizeIn){ | ||
111 | if(m_sizeIn && m_bsIn) | ||
112 | delete m_bsIn; | ||
113 | m_bsIn = new BYTE[m_sizeIn=sin]; | ||
114 | if(!m_bsIn) | ||
115 | return FALSE; | ||
116 | } | ||
117 | return TRUE; | ||
118 | } | ||
119 | |||
120 | |||
121 | WORD CICMPWS::m_icmpSeq = 0; | ||
122 | |||
123 | BOOL CICMPWS::Initialize() | ||
124 | { | ||
125 | if(m_socket!=INVALID_SOCKET) | ||
126 | Deinitialize(); | ||
127 | m_socket = socket(AF_INET,SOCK_RAW,1/*ICMP*/); | ||
128 | if(m_socket==INVALID_SOCKET) | ||
129 | return FALSE; | ||
130 | TRACE0("ICMP-WS Initialized\n"); | ||
131 | return TRUE; | ||
132 | } | ||
133 | void CICMPWS::Deinitialize() | ||
134 | { | ||
135 | if(m_socket!=INVALID_SOCKET){ | ||
136 | closesocket(m_socket); | ||
137 | m_socket=INVALID_SOCKET; | ||
138 | } | ||
139 | if(m_sizeOut && m_bsOut){ | ||
140 | delete m_bsOut; | ||
141 | m_bsOut = NULL; m_sizeOut = 0; | ||
142 | } | ||
143 | if(m_sizeIn && m_bsIn){ | ||
144 | delete m_bsIn; | ||
145 | m_bsIn = NULL; m_sizeIn = 0; | ||
146 | } | ||
147 | } | ||
148 | LONG CICMPWS::Ping(const in_addr host,const UINT packetSize, | ||
149 | const UINT timeOut,LPINT pStatus) | ||
150 | { | ||
151 | if(m_socket==INVALID_SOCKET){ | ||
152 | if(pStatus) | ||
153 | (*pStatus)=icmpNotInitialized; | ||
154 | } | ||
155 | VERIFY(AdjustBuffers(packetSize)); | ||
156 | icmp* pPacket = (icmp*)m_bsOut; | ||
157 | memset(pPacket,0,m_sizeOut); | ||
158 | pPacket->icmp_type = ICMP_ECHO; | ||
159 | pPacket->icmp_seq = m_icmpSeq++; | ||
160 | pPacket->icmp_id = (WORD)(::GetCurrentThreadId()&0xFFFF); | ||
161 | for(UINT tmp=0;tmp<packetSize;tmp++) | ||
162 | pPacket->icmp_data[tmp]=tmp&0xFF; | ||
163 | pPacket->icmp_cksum = cksum(pPacket,SIZE_ICMP_HDR+packetSize); | ||
164 | sockaddr_in to; | ||
165 | memset(&to,0,sizeof(to)); | ||
166 | to.sin_addr.s_addr = host.s_addr; | ||
167 | to.sin_family = AF_INET; | ||
168 | if(sendto(m_socket,(char*)pPacket,SIZE_ICMP_HDR+packetSize,0, | ||
169 | (SOCKADDR*)&to,sizeof(to)) != (int)(SIZE_ICMP_HDR+packetSize)){ | ||
170 | TRACE1("sendto: %lu\n",WSAGetLastError()); | ||
171 | if(pStatus) | ||
172 | (*pStatus)=icmpSocketError; | ||
173 | return -1; | ||
174 | } | ||
175 | DWORD sentTime = ::GetTickCount(); | ||
176 | sockaddr_in from; | ||
177 | memset(&from,0,sizeof(from)); | ||
178 | from.sin_family=AF_INET; | ||
179 | from.sin_addr.s_addr=INADDR_ANY; | ||
180 | fd_set fds; | ||
181 | FD_ZERO(&fds); | ||
182 | FD_SET(m_socket,&fds); | ||
183 | long lrv = -1; | ||
184 | INT rv = ipTimeOut; | ||
185 | for(;;){ | ||
186 | DWORD ct = ::GetTickCount(); | ||
187 | if((ct-sentTime)>=timeOut){ | ||
188 | TRACE0("Timeout\n"); | ||
189 | break; | ||
190 | } | ||
191 | timeval tv = { | ||
192 | (timeOut-ct+sentTime)/1000, | ||
193 | (timeOut-ct+sentTime)%1000 | ||
194 | };// tv_sec, tv_usec (secs,microsecs) | ||
195 | if(!select(m_socket,&fds,NULL,NULL,&tv)){ | ||
196 | TRACE1("select: %d\n",WSAGetLastError()); | ||
197 | break; | ||
198 | } | ||
199 | DWORD rtime = ::GetTickCount(); | ||
200 | ASSERT(FD_ISSET(m_socket,&fds)); | ||
201 | int fl = sizeof(from); | ||
202 | int rb = recvfrom(m_socket,(char*)m_bsIn,m_sizeIn,0,(SOCKADDR*)&from,&fl); | ||
203 | ip* pIP = (ip*)m_bsIn; | ||
204 | icmp* pICMP = (icmp*)&m_bsIn[sizeof(ip)]; | ||
205 | if(pICMP->icmp_id!=pPacket->icmp_id) | ||
206 | continue; | ||
207 | if(pICMP->icmp_seq!=pPacket->icmp_seq) | ||
208 | continue; | ||
209 | if(from.sin_addr.s_addr!=host.s_addr) | ||
210 | continue; | ||
211 | if(pICMP->icmp_type==ICMP_ECHOREPLY){ | ||
212 | lrv=rtime-sentTime; | ||
213 | rv=ipSuccess; | ||
214 | break; | ||
215 | } | ||
216 | rv = ipUnknown;// *** | ||
217 | break; | ||
218 | } | ||
219 | if(pStatus) | ||
220 | (*pStatus)=rv; | ||
221 | return lrv; | ||
222 | } | ||
223 | |||
224 | BOOL CICMPWS::AdjustBuffers(UINT packetSize) | ||
225 | { | ||
226 | if(!packetSize) | ||
227 | packetSize=0; | ||
228 | UINT osize = packetSize+SIZE_ICMP_HDR; | ||
229 | if(m_sizeOut<osize){ | ||
230 | if(m_sizeOut && m_bsOut) | ||
231 | delete m_bsOut; | ||
232 | m_bsOut = new BYTE[m_sizeOut=osize]; | ||
233 | if(!m_bsOut) | ||
234 | return FALSE; | ||
235 | } | ||
236 | UINT isize = osize+sizeof(ip); | ||
237 | if(m_sizeIn<isize){ | ||
238 | if(m_sizeIn && m_bsIn) | ||
239 | delete m_bsIn; | ||
240 | m_bsIn = new BYTE[m_sizeIn=isize]; | ||
241 | if(!m_bsIn) | ||
242 | return FALSE; | ||
243 | } | ||
244 | return TRUE; | ||
245 | } | ||
246 | |||
247 | WORD CICMPWS::cksum(LPVOID data,int count) | ||
248 | { | ||
249 | long lSum = 0; | ||
250 | WORD *pData = (WORD*)data; | ||
251 | while(count>0){ | ||
252 | if(count>1){ | ||
253 | lSum+=*(pData++); | ||
254 | count-=2; | ||
255 | }else{ | ||
256 | lSum+=((WORD)*(BYTE*)pData)&0xFF; | ||
257 | count--; | ||
258 | } | ||
259 | } | ||
260 | lSum = (lSum&0xFFFF)+(lSum>>16); | ||
261 | lSum += (lSum>>16); | ||
262 | return (~lSum)&0xFFFF; | ||
263 | } | ||
264 | |||
265 | CICMP* CICMP::CreateICMP() | ||
266 | { | ||
267 | if(m_mechanismus==_icmpUndetermined) | ||
268 | GuessMechanismus(); | ||
269 | switch(m_mechanismus){ | ||
270 | case _icmpWinsock: | ||
271 | return new CICMPWS; | ||
272 | break; | ||
273 | case _icmpDLL: | ||
274 | return new CICMPDll; | ||
275 | break; | ||
276 | } | ||
277 | return NULL; | ||
278 | } | ||
279 | |||
280 | void CICMP::GuessMechanismus() | ||
281 | { | ||
282 | m_mechanismus=_icmpUndetermined; | ||
283 | SOCKET testSocket = socket(AF_INET,SOCK_RAW,1); | ||
284 | if(testSocket!=INVALID_SOCKET){ | ||
285 | closesocket(testSocket); | ||
286 | m_mechanismus=_icmpWinsock; | ||
287 | }else{ | ||
288 | HINSTANCE hICMP = ::LoadLibraryEx("ICMP",NULL,0); | ||
289 | if(!hICMP) | ||
290 | return; | ||
291 | BOOL isThere = ( | ||
292 | ::GetProcAddress(hICMP,"IcmpCreateFile") | ||
293 | && ::GetProcAddress(hICMP,"IcmpSendEcho") | ||
294 | && ::GetProcAddress(hICMP,"IcmpCloseHandle") | ||
295 | ); | ||
296 | ::FreeLibrary(hICMP); | ||
297 | if(isThere) | ||
298 | m_mechanismus=_icmpDLL; | ||
299 | } | ||
300 | } \ No newline at end of file | ||