1
2 /***************************************************************************
3 * EchoServer.cc -- *
4 * *
5 ***********************IMPORTANT NMAP LICENSE TERMS************************
6 * *
7 * The Nmap Security Scanner is (C) 1996-2020 Insecure.Com LLC ("The Nmap *
8 * Project"). Nmap is also a registered trademark of the Nmap Project. *
9 * *
10 * This program is distributed under the terms of the Nmap Public Source *
11 * License (NPSL). The exact license text applying to a particular Nmap *
12 * release or source code control revision is contained in the LICENSE *
13 * file distributed with that version of Nmap or source code control *
14 * revision. More Nmap copyright/legal information is available from *
15 * https://nmap.org/book/man-legal.html, and further information on the *
16 * NPSL license itself can be found at https://nmap.org/npsl. This header *
17 * summarizes some key points from the Nmap license, but is no substitute *
18 * for the actual license text. *
19 * *
20 * Nmap is generally free for end users to download and use themselves, *
21 * including commercial use. It is available from https://nmap.org. *
22 * *
23 * The Nmap license generally prohibits companies from using and *
24 * redistributing Nmap in commercial products, but we sell a special Nmap *
25 * OEM Edition with a more permissive license and special features for *
26 * this purpose. See https://nmap.org/oem *
27 * *
28 * If you have received a written Nmap license agreement or contract *
29 * stating terms other than these (such as an Nmap OEM license), you may *
30 * choose to use and redistribute Nmap under those terms instead. *
31 * *
32 * The official Nmap Windows builds include the Npcap software *
33 * (https://npcap.org) for packet capture and transmission. It is under *
34 * separate license terms which forbid redistribution without special *
35 * permission. So the official Nmap Windows builds may not be *
36 * redistributed without special permission (such as an Nmap OEM *
37 * license). *
38 * *
39 * Source is provided to this software because we believe users have a *
40 * right to know exactly what a program is going to do before they run it. *
41 * This also allows you to audit the software for security holes. *
42 * *
43 * Source code also allows you to port Nmap to new platforms, fix bugs, *
44 * and add new features. You are highly encouraged to submit your *
45 * changes as a Github PR or by email to the dev@nmap.org mailing list *
46 * for possible incorporation into the main distribution. Unless you *
47 * specify otherwise, it is understood that you are offering us very *
48 * broad rights to use your submissions as described in the Nmap Public *
49 * Source License Contributor Agreement. This is important because we *
50 * fund the project by selling licenses with various terms, and also *
51 * because the inability to relicense code has caused devastating *
52 * problems for other Free Software projects (such as KDE and NASM). *
53 * *
54 * The free version of Nmap is distributed in the hope that it will be *
55 * useful, but WITHOUT ANY WARRANTY; without even the implied warranty of *
56 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. Warranties, *
57 * indemnification and commercial support are all available through the *
58 * Npcap OEM program--see https://nmap.org/oem. *
59 * *
60 ***************************************************************************/
61
62 #include "nping.h"
63 #include "EchoServer.h"
64 #include "EchoHeader.h"
65 #include "NEPContext.h"
66 #include <vector>
67 #include "nsock.h"
68 #include "output.h"
69 #include "NpingOps.h"
70 #include "ProbeMode.h"
71 #include <signal.h>
72
73 extern NpingOps o;
74 extern EchoServer es;
75
EchoServer()76 EchoServer::EchoServer() {
77 this->reset();
78 } /* End of EchoServer constructor */
79
80
~EchoServer()81 EchoServer::~EchoServer() {
82 } /* End of EchoServer destructor */
83
84
85 /** Sets every attribute to its default value- */
reset()86 void EchoServer::reset() {
87 this->client_ctx.clear();
88 this->client_id_count=-1;
89 } /* End of reset() */
90
91
92 /** Adds a new client context object to the server context list */
addClientContext(NEPContext ctx)93 int EchoServer::addClientContext(NEPContext ctx){
94 nping_print(DBG_4, "%s(ctx->id=%d)", __func__, ctx.getIdentifier());
95 this->client_ctx.push_back(ctx);
96 return OP_SUCCESS;
97 } /* End of addClientContext() */
98
99
100 /** Looks up the context of a given client, based on the supplied client ID.
101 * On success, it returns a pointer to the client's context object. NULL is
102 * returned when no context could be found. */
getClientContext(clientid_t clnt)103 NEPContext *EchoServer::getClientContext(clientid_t clnt){
104 nping_print(DBG_4, "%s(%d) %lu", __func__, clnt, (unsigned long)this->client_ctx.size());
105 for(unsigned int i=0; i<this->client_ctx.size(); i++){
106 if(this->client_ctx[i].getIdentifier() == clnt ){
107 nping_print(DBG_3, "Found client with ID #%d at p%d. Total clients %lu", clnt, i, (unsigned long)this->client_ctx.size());
108 return &(this->client_ctx[i]);
109 }
110 }
111 nping_print(DBG_3, "No client with ID #%d was found. Total clients %lu", clnt, (unsigned long)this->client_ctx.size());
112 return NULL;
113 } /* End of getClientContext() */
114
115
116 /** Looks up the context of a given client, based on the supplied nsock IOD.
117 * On success, it returns a pointer to the client's context object. NULL is
118 * returned when no context could be found. */
getClientContext(nsock_iod iod)119 NEPContext *EchoServer::getClientContext(nsock_iod iod){
120 nping_print(DBG_4, "%s()", __func__);
121 clientid_t *id=NULL;
122 if( (id=(clientid_t *)nsock_iod_get_udata(iod))==NULL )
123 return NULL;
124 else
125 return this->getClientContext(*id);
126 } /* End of getClientContext() */
127
128
129 /** Deletes context information associated with a given client. Returns
130 * OP_SUCCESS if the context object was successfully deleted or OP_FAILURE if
131 * the context could not be found. */
destroyClientContext(clientid_t clnt)132 int EchoServer::destroyClientContext(clientid_t clnt){
133 bool deleted=false;
134 std::vector<NEPContext>::iterator it;
135 /* Iterate through the context array and delete the one that belongs to clnt */
136 for ( it=this->client_ctx.begin(); it<this->client_ctx.end(); it++){
137 if(it->getIdentifier()==clnt){
138 this->client_ctx.erase(it);
139 deleted=true;
140 break;
141 }
142 }
143 return (deleted) ? OP_SUCCESS : OP_FAILURE;
144 } /* End of destroyClientContext() */
145
146
147 /** Returns the Nsock IOD associated with a given client ID. */
getClientNsockIOD(clientid_t clnt)148 nsock_iod EchoServer::getClientNsockIOD(clientid_t clnt){
149 nping_print(DBG_4, "%s(%d)", __func__, clnt);
150 NEPContext *ctx;
151 if((ctx=this->getClientContext(clnt))==NULL )
152 return NULL;
153 else
154 return ctx->getNsockIOD();
155 } /* End of getClientNsockIOD() */
156
157
158 /** Generates a new client identifier. This is used internally by the echo
159 * server, but this value is never sent over the wire (it has nothing to do
160 * with the NEP protocol). Each call to getNewClientID() generates a new
161 * identifier, so it should only be called once per client session.
162 * Warning: This code checks for an overflow and wraps the client id count back
163 * to zero if necessary. A given execution of a server should be able to handle
164 * 4,294,967,296 client sessions. Practically there is no way to achieve that
165 * number (it would be something like receiving one client session per second
166 * for 136 years, so relax!) However, it should be noted that this
167 * implementation makes no effort to handle re-used client identifiers, so
168 * there is a tiny chance that after the 4,294,967,296th client, the assigned
169 * number conflicts with an active session ;-) */
getNewClientID()170 clientid_t EchoServer::getNewClientID(){
171 nping_print(DBG_4, "%s()", __func__);
172 if(this->client_id_count==0xFFFF) /* Wrap back to zero. */
173 this->client_id_count=0;
174 else
175 this->client_id_count++;
176 return this->client_id_count;
177 } /* End of getNewClientID() */
178
179
180 /** Returns a socket suitable to be passed to accept() */
nep_listen_socket()181 int EchoServer::nep_listen_socket(){
182 nping_print(DBG_4, "%s()", __func__);
183 int one=1; /**< Dummy var for setsockopt() call */
184 int master_sd=-1; /**< Master socket. Server listens on it */
185 struct sockaddr_in server_addr4; /**< For our own IPv4 address */
186 struct sockaddr_in6 server_addr6; /**< For our own IPv6 address */
187 int port = o.getEchoPort();
188
189 /* Ignore SIGPIPE signal, received when a client disconnects suddenly and
190 *data is sent to it before noticing. */
191 #ifndef WIN32
192 signal(SIGPIPE, SIG_IGN);
193 #endif
194
195 /* AF_INET6 */
196 if( o.ipv6() ){
197
198 /* Obtain a regular TCP socket for IPv6 */
199 if( (master_sd=socket(AF_INET6, SOCK_STREAM, IPPROTO_TCP))<0 )
200 nping_fatal(QT_3, "Could not obtain AF_INET/SOCK_STREAM/IPPROTO_TCP socket");
201
202 /* Set SO_REUSEADDR on socket so the bind does not fail if we had used
203 * this port in a previous execution, not long ago. */
204 if( setsockopt(master_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int))!=0 )
205 nping_warning(QT_3, "Failed to set SO_REUSEADDR on master socket.");
206
207 memset(&server_addr6, 0, sizeof(struct sockaddr_in6));
208 server_addr6.sin6_addr = (o.spoofSource()) ? o.getIPv6SourceAddress() : in6addr_any;
209 server_addr6.sin6_family = AF_INET6;
210 server_addr6.sin6_port = htons(port);
211 server_addr6.sin6_flowinfo = 0;
212 #ifdef HAVE_SOCKADDR_IN6_SIN6_LEN
213 server_addr6.sin6_len = sizeof(struct sockaddr_in6);
214 #endif
215 /* Bind to local address and the specified port */
216 if( ::bind(master_sd, (struct sockaddr *)&server_addr6, sizeof(server_addr6)) != 0 ){
217 nping_warning(QT_3, "Failed to bind to source address %s. Trying to bind to port %d...", IPtoa(server_addr6.sin6_addr), port);
218 /* If the bind failed for the supplied address, just try again with in6addr_any */
219 if( o.spoofSource() ){
220 server_addr6.sin6_addr = in6addr_any;
221 if( ::bind(master_sd, (struct sockaddr *)&server_addr6, sizeof(server_addr6)) != 0 ){
222 nping_fatal(QT_3, "Could not bind to port %d (%s).", port, strerror(errno));
223 }else{
224 nping_print(VB_1, "Server bound to port %d", port);
225 }
226 }
227 }else{
228 nping_print(VB_1, "Server bound to %s:%d", IPtoa(server_addr6.sin6_addr), port);
229 }
230
231
232 /* AF_INET */
233 }else{
234
235 /* Obtain a regular TCP socket for IPv4 */
236 if( (master_sd=socket(AF_INET, SOCK_STREAM, IPPROTO_TCP))<0 )
237 nping_fatal(QT_3, "Could not obtain AF_INET/SOCK_STREAM/IPPROTO_TCP socket");
238
239 /* Set SO_REUSEADDR on socket so the bind does not fail if we had used
240 * this port in a previous execution, not long ago. */
241 if( setsockopt(master_sd, SOL_SOCKET, SO_REUSEADDR, (char *) &one, sizeof(int))!=0 )
242 nping_warning(QT_3, "Failed to set SO_REUSEADDR on master socket.");
243
244
245 memset(&server_addr4, 0, sizeof(struct sockaddr_in));
246 server_addr4.sin_family = AF_INET;
247 server_addr4.sin_port = htons(port);
248 server_addr4.sin_addr.s_addr = (o.spoofSource()) ? o.getIPv4SourceAddress().s_addr : INADDR_ANY;
249 #ifdef HAVE_SOCKADDR_IN_SIN_LEN
250 server_addr4.sin_len = sizeof(struct sockaddr_in);
251 #endif
252
253 /* Bind to local address and the specified port */
254 if( ::bind(master_sd, (struct sockaddr *)&server_addr4, sizeof(server_addr4)) != 0 ){
255 nping_warning(QT_3, "Failed to bind to source address %s. Trying to bind to port %d...", IPtoa(server_addr4.sin_addr), port);
256 /* If the bind failed for the supplied address, just try again with in6addr_any */
257 if( o.spoofSource() ){
258 server_addr4.sin_addr.s_addr=INADDR_ANY;
259 if( ::bind(master_sd, (struct sockaddr *)&server_addr4, sizeof(server_addr4)) != 0 ){
260 nping_fatal(QT_3, "Could not bind to port %d (%s).", port, strerror(errno));
261 }else{
262 nping_print(VB_1, "Server bound to port %d", port);
263 }
264 }
265 }else{
266 nping_print(VB_1, "Server bound to %s:%d", IPtoa(server_addr4.sin_addr), port);
267 }
268
269 }
270
271 /* Listen for incoming TCP connections... */
272 if( listen(master_sd, LISTEN_QUEUE_SIZE) != 0 ){
273 nping_fatal(QT_3, "[E] Failed to listen() on port %d (%s)", port, strerror(errno));
274 }
275 return master_sd;
276 } /* End of nep_listen() */
277
278
279
280 /* Weighting factors */
281 #define FACTOR_IPv4_TOS 1.0
282 #define FACTOR_IPv4_PROTO 0.9
283 #define FACTOR_IPv4_ID 2.5
284 #define FACTOR_IPv4_FRAGOFF 1.0
285 #define FACTOR_IPv6_TCLASS 1.0
286 #define FACTOR_IPv6_FLOW 2.5
287 #define FACTOR_IPv6_NHDR 0.9
288 #define FACTOR_TCP_SPORT 1.5
289 #define FACTOR_TCP_DPORT 1.0
290 #define FACTOR_TCP_SEQ 2.0
291 #define FACTOR_TCP_ACK 1.0
292 #define FACTOR_TCP_FLAGS 1.0
293 #define FACTOR_TCP_WIN 1.0
294 #define FACTOR_TCP_URP 1.0
295 #define FACTOR_ICMP_TYPE 1.0
296 #define FACTOR_ICMP_CODE 1.0
297 #define FACTOR_UDP_SPORT 1.0
298 #define FACTOR_UDP_DPORT 1.0
299 #define FACTOR_UDP_LEN 1.0
300 #define FACTOR_PAYLOAD_MAGIC 1.0
301
302 #define ZERO_PENALTY 0.3
303
304 #define MIN_ACCEPTABLE_SCORE_TCP 10.0
305 #define MIN_ACCEPTABLE_SCORE_UDP 8.0
306 #define MIN_ACCEPTABLE_SCORE_ICMP 6.0
307
nep_match_headers(IPv4Header * ip4,IPv6Header * ip6,TCPHeader * tcp,UDPHeader * udp,ICMPv4Header * icmp4,RawData * payload)308 clientid_t EchoServer::nep_match_headers(IPv4Header *ip4, IPv6Header *ip6, TCPHeader *tcp, UDPHeader *udp, ICMPv4Header *icmp4, RawData *payload){
309 nping_print(DBG_4, "%s(%p,%p,%p,%p,%p,%p)", __func__, ip4, ip6, tcp, udp, icmp4, payload);
310 unsigned int i=0, k=0;
311 u8 *buff=NULL;
312 int bufflen=-1;
313 NEPContext *ctx;
314 fspec_t *fspec;
315 float current_score=0;
316 float candidate_score=-1;
317 float minimum_score=0;
318 clientid_t candidate=-1;
319
320 /* Iterate through the list of connected clients */
321 for(i=0; i<this->client_ctx.size(); i++ ){
322 current_score=0;
323 ctx=&(this->client_ctx[i]);
324 nping_print(DBG_2, "%s() Trying to match packet against client #%d", __func__, ctx->getIdentifier());
325 if( ctx->ready() ){
326 /* Iterate through client's list of packet field specifiers */
327 for(k=0; (fspec=ctx->getClientFieldSpec(k))!=NULL; k++){
328 switch(fspec->field){
329 case PSPEC_IPv4_TOS:
330 if(ip4==NULL)break;
331 nping_print(DBG_3, "%s() Trying to match IP TOS", __func__);
332 if( ip4->getTOS()==fspec->value[0] ){
333 nping_print(DBG_3, "[Match] IP TOS=%02x", ip4->getTOS());
334 current_score += 1 * FACTOR_IPv4_TOS * ((ip4->getTOS()==0) ? ZERO_PENALTY : 1);
335 }
336 break;
337 case PSPEC_IPv4_PROTO:
338 if(ip4==NULL)break;
339 nping_print(DBG_3, "%s() Trying to match IP Next Protocol", __func__);
340 if( ip4->getNextProto()==fspec->value[0] ){
341 nping_print(DBG_3, "[Match] IP Proto=%02x", ip4->getNextProto());
342 current_score += 1 * FACTOR_IPv4_PROTO;
343 }
344 break;
345 case PSPEC_IPv4_ID:
346 if(ip4==NULL)break;
347 nping_print(DBG_3, "%s() Trying to match IP Identification", __func__);
348 if( ip4->getIdentification()==ntohs( *((u16 *)fspec->value) ) ){
349 nping_print(DBG_3, "[Match] IP Id=%u", ip4->getIdentification());
350 current_score += 2 * FACTOR_IPv4_ID;
351 }
352 break;
353 case PSPEC_IPv4_FRAGOFF:
354 if(ip4==NULL)break;
355 nping_print(DBG_3, "%s() Trying to match IP Fragment offset", __func__);
356 if( ip4->getFragOffset()==ntohs( *((u16 *)fspec->value)) ){
357 nping_print(DBG_3, "[Match] IP FragOff=%u", ip4->getFragOffset() );
358 current_score += 2 * FACTOR_IPv4_FRAGOFF * ((ip4->getFragOffset()==0) ? ZERO_PENALTY : 1);
359 }
360 break;
361
362 case PSPEC_IPv6_TCLASS:
363 if(ip6==NULL)break;
364 nping_print(DBG_3, "%s() Trying to match IPv6 Traffic Class", __func__);
365 if( ip6->getTrafficClass()==fspec->value[0] ){
366 nping_print(DBG_3, "[Match] IPv6 TClass=%u", ip6->getTrafficClass() );
367 current_score += 1 * FACTOR_IPv6_TCLASS * ((ip6->getTrafficClass()==0) ? ZERO_PENALTY : 1);
368 }
369 break;
370 case PSPEC_IPv6_FLOW:
371 if(ip6==NULL)break;
372 nping_print(DBG_3, "%s() Trying to match IPv6 Flow Label", __func__);
373 if( ip6->getFlowLabel()==ntohl( *((u32 *)fspec->value)) ){
374 nping_print(DBG_3, "[Match] IPv6 Flow=%lu", (long unsigned)ip6->getFlowLabel() );
375 current_score += 3 * FACTOR_IPv6_FLOW * ((ip6->getFlowLabel()==0) ? ZERO_PENALTY : 1);
376 }
377 break;
378 case PSPEC_IPv6_NHDR:
379 if(ip6==NULL)break;
380 nping_print(DBG_3, "%s() Trying to match IPv6 Next Header", __func__);
381 if( ip6->getNextHeader()==fspec->value[0] ){
382 nping_print(DBG_3, "[Match] IPv6 NextHdr=%02x", ip6->getNextHeader());
383 current_score += 1 * FACTOR_IPv6_NHDR;
384 }
385 break;
386 case PSPEC_TCP_SPORT:
387 if(tcp==NULL)break;
388 nping_print(DBG_3, "%s() Trying to match TCP Source Port", __func__);
389 if( tcp->getSourcePort()==ntohs( *((u16 *)fspec->value) ) ){
390 nping_print(DBG_3, "[Match] TCP Src=%u", tcp->getSourcePort());
391 current_score += 2 * FACTOR_TCP_SPORT;
392 }
393 break;
394 case PSPEC_TCP_DPORT:
395 if(tcp==NULL)break;
396 nping_print(DBG_3, "%s() Trying to match TCP Destination Port", __func__);
397 if( tcp->getDestinationPort()==ntohs( *((u16 *)fspec->value) ) ){
398 nping_print(DBG_3, "[Match] TCP Dst=%u", tcp->getDestinationPort());
399 current_score += 2 * FACTOR_TCP_DPORT;
400 }
401 break;
402 case PSPEC_TCP_SEQ:
403 if(tcp==NULL)break;
404 nping_print(DBG_3, "%s() Trying to match TCP Sequence Number", __func__);
405 if( tcp->getSeq()==ntohl( *((u32 *)fspec->value) ) ){
406 nping_print(DBG_3, "[Match] TCP Seq=%u", tcp->getSeq());
407 current_score += 4 * FACTOR_TCP_SEQ * ((tcp->getSeq()==0) ? ZERO_PENALTY : 1);
408 }
409 break;
410 case PSPEC_TCP_ACK:
411 if(tcp==NULL)break;
412 nping_print(DBG_3, "%s() Trying to match TCP Acknowledgment", __func__);
413 if( tcp->getAck()==ntohl( *((u32 *)fspec->value) ) ){
414 nping_print(DBG_3, "[Match] TCP Ack=%u", tcp->getAck());
415 current_score += 4 * FACTOR_TCP_ACK * ((tcp->getAck()==0) ? ZERO_PENALTY : 1);
416 }
417 break;
418 case PSPEC_TCP_FLAGS:
419 if(tcp==NULL)break;
420 if( tcp->getFlags()==fspec->value[0] ){
421 nping_print(DBG_3, "%s() Trying to match TCP Flags", __func__);
422 nping_print(DBG_3, "[Match] TCP Flags=%02x", tcp->getFlags());
423 current_score += 1 * FACTOR_TCP_FLAGS;
424 }
425 break;
426 case PSPEC_TCP_WIN:
427 if(tcp==NULL)break;
428 nping_print(DBG_3, "%s() Trying to match TCP Window", __func__);
429 if( tcp->getWindow()==ntohs( *((u16 *)fspec->value) ) ){
430 nping_print(DBG_3, "[Match] TCP Win=%u", tcp->getWindow());
431 current_score += 2 * FACTOR_TCP_WIN * ((tcp->getWindow()==0) ? ZERO_PENALTY : 1);
432 }
433 break;
434 case PSPEC_TCP_URP:
435 if(tcp==NULL)break;
436 nping_print(DBG_3, "%s() Trying to match TCP Urgent Pointer", __func__);
437 if( tcp->getUrgPointer()==ntohs( *((u16 *)fspec->value) ) ){
438 nping_print(DBG_3, "[Match] TCP Win=%u", tcp->getUrgPointer());
439 current_score += 2 * FACTOR_TCP_URP * ((tcp->getUrgPointer()==0) ? ZERO_PENALTY : 1);
440 }
441 break;
442 case PSPEC_ICMP_TYPE:
443 if(icmp4==NULL)break;
444 nping_print(DBG_3, "%s() Trying to match ICMPv4 Type", __func__);
445 if( icmp4->getType()==fspec->value[0] ){
446 nping_print(DBG_3, "[Match] ICMPv4 Type=%02x", icmp4->getType());
447 current_score += 1 * FACTOR_ICMP_TYPE;
448 }
449 break;
450 case PSPEC_ICMP_CODE:
451 if(icmp4==NULL)break;
452 nping_print(DBG_3, "%s() Trying to match ICMPv4 Code", __func__);
453 if( icmp4->getCode()==fspec->value[0] ){
454 nping_print(DBG_3, "[Match] ICMPv4 Code=%02x", icmp4->getCode());
455 current_score += 1 * FACTOR_ICMP_CODE * ((icmp4->getCode()==0) ? ZERO_PENALTY : 1);
456 }
457 break;
458 case PSPEC_UDP_SPORT:
459 if(udp==NULL)break;
460 nping_print(DBG_3, "%s() Trying to match UDP Source Port", __func__);
461 if( udp->getSourcePort()==ntohs( *((u16 *)fspec->value) ) ){
462 nping_print(DBG_3, "[Match] UDP Src=%u", udp->getSourcePort());
463 current_score += 2 * FACTOR_UDP_SPORT;
464 }
465 break;
466 case PSPEC_UDP_DPORT:
467 if(udp==NULL)break;
468 nping_print(DBG_3, "%s() Trying to match UDP Destination Port", __func__);
469 if( udp->getDestinationPort()==ntohs( *((u16 *)fspec->value) ) ){
470 nping_print(DBG_3, "[Match] UDP Dst=%u", udp->getDestinationPort());
471 current_score += 2 * FACTOR_UDP_DPORT;
472 }
473 break;
474 case PSPEC_UDP_LEN:
475 if(udp==NULL)break;
476 nping_print(DBG_3, "%s() Trying to match UDP Length", __func__);
477 if( udp->getTotalLength()==ntohs( *((u16 *)fspec->value) ) ){
478 nping_print(DBG_3, "[Match] UDP Len=%u", udp->getTotalLength());
479 current_score += 2 * FACTOR_UDP_LEN * ((udp->getTotalLength()==8) ? ZERO_PENALTY : 1);
480 }
481 break;
482 case PSPEC_PAYLOAD_MAGIC:
483 if(payload==NULL)break;
484 nping_print(DBG_3, "%s() Trying to match Payload Magic value", __func__);
485 buff=payload->getBinaryBuffer(&bufflen);
486 if(buff==NULL || bufflen<=0 || fspec->len>bufflen)
487 break;
488 if( memcmp(buff, fspec->value, fspec->len)==0 ){
489 nping_print(DBG_3|NO_NEWLINE, "[Match] Payload magic=0x");
490 for(unsigned int i=0; i<fspec->len; i++)
491 nping_print(DBG_3|NO_NEWLINE,"%02x", fspec->value[i]);
492 nping_print(DBG_3, ";");
493 /* The payload magic may affect the score only between
494 * zero and 4 bytes. This is done to prevent long
495 * common strings like "GET / HTTP/1.1\r\n"
496 * increasing the score a lot and cause problems for
497 * the matching logic. */
498 current_score+= MIN(4, fspec->len)*FACTOR_PAYLOAD_MAGIC;
499 }
500 break;
501
502 default:
503 nping_warning(QT_2, "Bogus field specifier found in client #%d context. Please report a bug", ctx->getIdentifier());
504 break;
505 }
506 } /* End of field specifiers loop */
507
508 nping_print(DBG_3, "%s() current_score=%.02f candidate_score=%.02f", __func__, current_score, candidate_score);
509 if( (current_score>0) && (current_score>=candidate_score)){
510 candidate_score=current_score;
511 candidate=ctx->getIdentifier();
512 nping_print(DBG_3, "%s() Found better candidate (client #%d; score=%.02f)", __func__, candidate, candidate_score);
513 }
514 }
515 } /* End of connected clients loop */
516
517 if( tcp!=NULL )
518 minimum_score=MIN_ACCEPTABLE_SCORE_TCP;
519 else if (udp!=NULL)
520 minimum_score=MIN_ACCEPTABLE_SCORE_UDP;
521 else if(icmp4!=NULL)
522 minimum_score=MIN_ACCEPTABLE_SCORE_ICMP;
523 else
524 minimum_score=10000;
525
526 /* Check if we managed to match packet and client */
527 if (candidate>=0 && candidate_score>=minimum_score){
528 nping_print(DBG_2, "%s() Packet matched successfully with client #%d", __func__, candidate);
529 return candidate;
530 }else{
531 if(candidate<0)
532 nping_print(DBG_2, "%s() Couldn't match packet with any client.", __func__);
533 else
534 nping_print(DBG_2, "%s() Found matching client but score is too low. Discarded.", __func__);
535 return CLIENT_NOT_FOUND;
536 }
537 return CLIENT_NOT_FOUND;
538 } /* End of nep_match_ipv4() */
539
540
nep_match_packet(const u8 * pkt,size_t pktlen)541 clientid_t EchoServer::nep_match_packet(const u8 *pkt, size_t pktlen){
542 nping_print(DBG_4, "%s(%p, %lu)", __func__, pkt, (long unsigned)pktlen);
543 int iplen=0, ip6len=0, tcplen=0, udplen=0;
544 bool payload_included=false;
545 IPv4Header ip4;
546 IPv6Header ip6;
547 TCPHeader tcp;
548 UDPHeader udp;
549 ICMPv4Header icmp4;
550 RawData payload;
551
552 if(this->client_id_count<0){
553 nping_print(DBG_1, "Error trying to match the packet. No clients connected.");
554 return CLIENT_NOT_FOUND;
555 }else if(pktlen<IP_HEADER_LEN){
556 nping_print(DBG_1, "Error trying to match the packet. Bogus packet received (too short)");
557 return CLIENT_NOT_FOUND;
558 }
559
560 /* Determine IP version */
561 if (ip4.storeRecvData(pkt, pktlen)==OP_FAILURE)
562 return CLIENT_NOT_FOUND;
563
564 if(ip4.getVersion()==0x04){
565
566 nping_print(DBG_2, "Recv packet is IPv4. Trying to find a matching client.");
567 if( (iplen=ip4.validate())==OP_FAILURE){
568 return CLIENT_NOT_FOUND;
569 }else{
570 switch( ip4.getNextProto() ){
571 case 1: // ICMP
572 if( icmp4.storeRecvData(pkt+iplen, pktlen-iplen)==OP_FAILURE )
573 return CLIENT_NOT_FOUND;
574 else
575 return this->nep_match_headers(&ip4, NULL, NULL, NULL, &icmp4, NULL);
576 break;
577
578 case 6: // TCP
579 if( tcp.storeRecvData(pkt+iplen, pktlen-iplen)==OP_FAILURE ){
580 return CLIENT_NOT_FOUND;
581 }else{
582 if( (tcplen=tcp.validate())==OP_FAILURE){
583 return CLIENT_NOT_FOUND;
584 }else{
585 if( (int)pktlen > (iplen+tcplen) ){
586 if( payload.storeRecvData(pkt+iplen+tcplen, pktlen-iplen-tcplen)!=OP_FAILURE)
587 payload_included=true;
588 }
589 if(payload_included)
590 return this->nep_match_headers(&ip4, NULL, &tcp, NULL, NULL, &payload);
591 else
592 return this->nep_match_headers(&ip4, NULL, &tcp, NULL, NULL, NULL);
593 }
594 }
595 break;
596
597 case 17: // UDP
598 if( udp.storeRecvData(pkt+iplen, pktlen-iplen)==OP_FAILURE ){
599 return CLIENT_NOT_FOUND;
600 }else{
601 if( (udplen=udp.validate())==OP_FAILURE){
602 return CLIENT_NOT_FOUND;
603 }else{
604 if( (int)pktlen > (iplen+udplen) ){
605 if( payload.storeRecvData(pkt+iplen+udplen, pktlen-iplen-udplen)!=OP_FAILURE)
606 payload_included=true;
607 }
608 if(payload_included)
609 return this->nep_match_headers(&ip4, NULL, NULL, &udp, NULL, &payload);
610 else
611 return this->nep_match_headers(&ip4, NULL, NULL, &udp, NULL, NULL);
612 }
613 }
614 break;
615
616 case 41: /* IPv6 encapsulated in the IPv4 datagram! */
617 if( ip6.storeRecvData(pkt+iplen, pktlen-iplen)==OP_FAILURE ){
618 return CLIENT_NOT_FOUND;
619 }else{
620 if( (ip6len=ip6.validate())==OP_FAILURE){
621 return CLIENT_NOT_FOUND;
622 }else{
623 switch( ip6.getNextHeader() ){
624 case 58: // ICMPv6
625 nping_print(DBG_4, "Encapsulated IPv4{ IPv6{ ICMPv6 } } received. Not supported.");
626 return CLIENT_NOT_FOUND;
627 break;
628
629 case 6: // TCP
630 if( tcp.storeRecvData(pkt+ip6len+iplen, pktlen-ip6len-iplen)==OP_FAILURE ){
631 return CLIENT_NOT_FOUND;
632 }else{
633 if( (tcplen=tcp.validate())==OP_FAILURE){
634 return CLIENT_NOT_FOUND;
635 }else{
636 if( (int)pktlen > (ip6len+iplen+tcplen) ){
637 if( payload.storeRecvData(pkt+ip6len+iplen+tcplen, pktlen-ip6len-iplen-tcplen)!=OP_FAILURE)
638 payload_included=true;
639 }
640 if(payload_included)
641 return this->nep_match_headers(&ip4, &ip6, &tcp, NULL, NULL, &payload);
642 else
643 return this->nep_match_headers(&ip4, &ip6, &tcp, NULL, NULL, NULL);
644 }
645 }
646 break;
647
648 case 17: // UDP
649 if( udp.storeRecvData(pkt+ip6len+iplen, pktlen-ip6len-iplen)==OP_FAILURE ){
650 return CLIENT_NOT_FOUND;
651 }else{
652 if( (udplen=udp.validate())==OP_FAILURE){
653 return CLIENT_NOT_FOUND;
654 }else{
655 if( (int)pktlen > (ip6len+iplen+udplen) ){
656 if( payload.storeRecvData(pkt+ip6len+iplen+udplen, pktlen-ip6len-iplen-udplen)!=OP_FAILURE)
657 payload_included=true;
658 }
659 if(payload_included)
660 return this->nep_match_headers(&ip4, &ip6, NULL, &udp, NULL, &payload);
661 else
662 return this->nep_match_headers(&ip4, &ip6, NULL, &udp, NULL, NULL);
663 }
664 }
665 break;
666
667 default:
668 return CLIENT_NOT_FOUND;
669 break;
670 }
671 }
672 }
673 break;
674
675 default:
676 return CLIENT_NOT_FOUND;
677 break;
678 }
679 }
680 }else if(ip4.getVersion()==0x06){
681
682 nping_print(DBG_2, "Recv packet is IPv6. Trying to find a matching client.");
683 if (ip6.storeRecvData(pkt, pktlen)==OP_FAILURE)
684 return CLIENT_NOT_FOUND;
685
686 if( (ip6len=ip6.validate())==OP_FAILURE )
687 return CLIENT_NOT_FOUND;
688
689 switch( ip6.getNextHeader() ){
690 case 58: // ICMPv6
691 nping_print(DBG_4, "Received ICMPv6 packet. Not yet supported.");
692 return CLIENT_NOT_FOUND;
693 break;
694
695 case 6: // TCP
696 if( tcp.storeRecvData(pkt+ip6len, pktlen-ip6len)==OP_FAILURE ){
697 return CLIENT_NOT_FOUND;
698 }else{
699 if( (tcplen=tcp.validate())==OP_FAILURE){
700 return CLIENT_NOT_FOUND;
701 }else{
702 if( (int)pktlen > (ip6len+tcplen) ){
703 if( payload.storeRecvData(pkt+ip6len+tcplen, pktlen-ip6len-tcplen)!=OP_FAILURE)
704 payload_included=true;
705 }
706 if(payload_included)
707 return this->nep_match_headers(NULL, &ip6, &tcp, NULL, NULL, &payload);
708 else
709 return this->nep_match_headers(NULL, &ip6, &tcp, NULL, NULL, NULL);
710 }
711 }
712 break;
713
714 case 17: // UDP
715 if( udp.storeRecvData(pkt+ip6len, pktlen-ip6len)==OP_FAILURE ){
716 return CLIENT_NOT_FOUND;
717 }else{
718 if( (udplen=udp.validate())==OP_FAILURE){
719 return CLIENT_NOT_FOUND;
720 }else{
721 if( (int)pktlen > (ip6len+udplen) ){
722 if( payload.storeRecvData(pkt+ip6len+udplen, pktlen-ip6len-udplen)!=OP_FAILURE)
723 payload_included=true;
724 }
725 if(payload_included)
726 return this->nep_match_headers(NULL, &ip6, NULL, &udp, NULL, &payload);
727 else
728 return this->nep_match_headers(NULL, &ip6, NULL, &udp, NULL, NULL);
729 }
730 }
731 break;
732
733 case 4: /* IPv4 encapsulated in the IPv6 datagram */
734 if( ip4.storeRecvData(pkt+ip6len, pktlen-ip6len)==OP_FAILURE ){
735 return CLIENT_NOT_FOUND;
736 }else{
737 if( (iplen=ip4.validate())==OP_FAILURE){
738 return CLIENT_NOT_FOUND;
739 }else{
740 switch( ip4.getNextProto() ){
741 case 1: // ICMP
742 if( icmp4.storeRecvData(pkt+ip6len+iplen, pktlen-ip6len-iplen)==OP_FAILURE )
743 return CLIENT_NOT_FOUND;
744 else
745 return this->nep_match_headers(&ip4, &ip6, NULL, NULL, &icmp4, NULL);
746 break;
747
748 case 6: // TCP
749 if( tcp.storeRecvData(pkt+ip6len+iplen, pktlen-ip6len-iplen)==OP_FAILURE ){
750 return CLIENT_NOT_FOUND;
751 }else{
752 if( (tcplen=tcp.validate())==OP_FAILURE){
753 return CLIENT_NOT_FOUND;
754 }else{
755 if( (int)pktlen > (ip6len+iplen+tcplen) ){
756 if( payload.storeRecvData(pkt+ip6len+iplen+tcplen, pktlen-ip6len-iplen-tcplen)!=OP_FAILURE)
757 payload_included=true;
758 }
759 if(payload_included)
760 return this->nep_match_headers(&ip4, &ip6, &tcp, NULL, NULL, &payload);
761 else
762 return this->nep_match_headers(&ip4, &ip6, &tcp, NULL, NULL, NULL);
763 }
764 }
765 break;
766
767 case 17: // UDP
768 if( udp.storeRecvData(pkt+ip6len+iplen, pktlen-ip6len-iplen)==OP_FAILURE ){
769 return CLIENT_NOT_FOUND;
770 }else{
771 if( (udplen=udp.validate())==OP_FAILURE){
772 return CLIENT_NOT_FOUND;
773 }else{
774 if( (int)pktlen > (ip6len+iplen+udplen) ){
775 if( payload.storeRecvData(pkt+ip6len+iplen+udplen, pktlen-ip6len-iplen-udplen)!=OP_FAILURE)
776 payload_included=true;
777 }
778 if(payload_included)
779 return this->nep_match_headers(&ip4, &ip6, NULL, &udp, NULL, &payload);
780 else
781 return this->nep_match_headers(&ip4, &ip6, NULL, &udp, NULL, NULL);
782 }
783 }
784 break;
785
786 default:
787 return CLIENT_NOT_FOUND;
788 break;
789 }
790 }
791 }
792 break;
793
794 default:
795 return CLIENT_NOT_FOUND;
796 break;
797 }
798 }else{
799 nping_print(DBG_2, "Received packet is not IP: Discarded.");
800 return CLIENT_NOT_FOUND;
801 }
802 return CLIENT_NOT_FOUND;
803 } /* End of nep_match_packet() */
804
805
nep_capture_handler(nsock_pool nsp,nsock_event nse,void * param)806 int EchoServer::nep_capture_handler(nsock_pool nsp, nsock_event nse, void *param){
807 nping_print(DBG_4, "%s()", __func__);
808 clientid_t clnt=CLIENT_NOT_FOUND;
809 const unsigned char *packet=NULL;
810 const unsigned char *link=NULL;
811 nsock_iod nsi = nse_iod(nse);
812 struct timeval pcaptime;
813 nsock_iod clnt_iod=NULL;
814 NEPContext *ctx=NULL;
815 EchoHeader pkt_out;
816 size_t linklen=0;
817 size_t packetlen=0;
818 handler_arg_t arg;
819 arg.me=this;
820 arg.param=NULL;
821
822 /* If there are connected clients, schedule another packet capture event */
823 if(this->client_ctx.size()>0){
824 nsock_pcap_read_packet(nsp, nsi, capture_handler, NSOCK_INFINITE, &arg);
825 nping_print(DBG_3, "Scheduled next capture event");
826 }
827
828 /* Get the actual captured packet */
829 nse_readpcap(nse, &link, &linklen, &packet, &packetlen, NULL, &pcaptime);
830 nping_print(DBG_3, "Captured %lu bytes", (unsigned long)packetlen);
831
832 /* Update Rx stats */
833 o.stats.addRecvPacket(packetlen);
834
835 /* Try to match received packet with a connected client. */
836 if( (clnt=this->nep_match_packet(packet, packetlen)) == CLIENT_NOT_FOUND ){
837 nping_print(DBG_3, "Couldn't match captured packet with a client");
838 return OP_FAILURE;
839 }else{
840 nping_print(DBG_4, "Captured packet belongs to client #%d", clnt);
841 }
842
843 /* Fetch client context */
844 if( (ctx=this->getClientContext(clnt)) == NULL ){
845 nping_print(DBG_2, "Error: no context found for client #%d", clnt);
846 return OP_FAILURE;
847 }
848
849 /* Lookup client's IOD */
850 if( (clnt_iod=ctx->getNsockIOD()) == NULL ){
851 nping_print(DBG_2, "Error: no IOD found for client #%d", clnt);
852 return OP_FAILURE;
853 }
854
855 if( ctx->ready() ){
856 this->generate_echo(&pkt_out, packet, packetlen, ctx);
857 nsock_write(nsp, clnt_iod, echo_handler, NSOCK_INFINITE, NULL, (const char *)pkt_out.getBinaryBuffer(), pkt_out.getLen());
858 o.stats.addEchoedPacket(packetlen);
859 }
860 return OP_SUCCESS;
861 } /* End of nep_capture_handler() */
862
863
nep_echo_handler(nsock_pool nsp,nsock_event nse,void * param)864 int EchoServer::nep_echo_handler(nsock_pool nsp, nsock_event nse, void *param){
865 nping_print(DBG_4, "%s()", __func__);
866 enum nse_status status=nse_status(nse);
867 if (status!=NSE_STATUS_SUCCESS){
868 nping_print(DBG_1, "Couldn't send NEP_ECHO. Terminating client session\n");
869 this->nep_session_ended_handler(nsp, nse, param);
870 }else{
871 nping_print(DBG_1, "SENT: NEP_ECHO");
872 }
873 return OP_SUCCESS;
874 } /* End of nep_echo_handler() */
875
876
nep_hs_server_handler(nsock_pool nsp,nsock_event nse,void * param)877 int EchoServer::nep_hs_server_handler(nsock_pool nsp, nsock_event nse, void *param){
878 nping_print(DBG_4, "%s()", __func__);
879 nsock_iod nsi = nse_iod(nse);
880 NEPContext *ctx=NULL;
881 enum nse_status status=nse_status(nse);
882 if (status!=NSE_STATUS_SUCCESS){
883 nping_print(DBG_1, "Couldn't send NEP_HANDSHAKE_SERVER. Terminating client session\n");
884 this->nep_session_ended_handler(nsp, nse, param);
885 return OP_FAILURE;
886 }
887 /* Lookup client context and schedule a read operation to receive a
888 * NEP_HANDSHAKE_CLIENT message */
889 if( (ctx=this->getClientContext(nsi))!=NULL ){
890 ctx->setState(STATE_HS_SERVER_SENT);
891 nping_print(DBG_1, "SENT: NEP_HANDSHAKE_SERVER to %s", IPtoa(ctx->getAddress()));
892 nsock_readbytes(nsp, nsi, hs_client_handler, NSOCK_INFINITE, NULL, NEP_HANDSHAKE_CLIENT_LEN);
893 }
894 return OP_SUCCESS;
895 } /* End of nep_hs_server_handler() */
896
897
nep_hs_client_handler(nsock_pool nsp,nsock_event nse,void * param)898 int EchoServer::nep_hs_client_handler(nsock_pool nsp, nsock_event nse, void *param){
899 nping_print(DBG_4, "%s()", __func__);
900 nsock_iod nsi = nse_iod(nse);
901 NEPContext *ctx=NULL;
902 EchoHeader pkt_out;
903 u8 *inbuff=NULL;
904 int inlen=0;
905 enum nse_status status=nse_status(nse);
906 if (status!=NSE_STATUS_SUCCESS){
907 nping_print(DBG_1, "Failed to receive NEP_HANDSHAKE_CLIENT. Terminating client session");
908 this->nep_session_ended_handler(nsp, nse, param);
909 return OP_FAILURE;
910 }else{
911 nping_print(DBG_1, "RCVD: NEP_HANDSHAKE_CLIENT");
912 }
913
914 /* Lookup client context */
915 if( (ctx=this->getClientContext(nsi))==NULL ){
916 this->nep_session_ended_handler(nsp, nse, param);
917 return OP_FAILURE;
918 }
919
920 /* Ask nsock to provide received data */
921 if( (inbuff=(u8 *)nse_readbuf(nse, &inlen))==NULL ){
922 this->nep_session_ended_handler(nsp, nse, param);
923 return OP_FAILURE;
924 }
925
926 /* Validate received NEP_HANDSHAKE_CLIENT */
927 if( this->parse_hs_client(inbuff, inlen, ctx)!=OP_SUCCESS ){
928 this->nep_session_ended_handler(nsp, nse, param);
929 return OP_FAILURE;
930 }
931 ctx->setState(STATE_HS_FINAL_SENT);
932
933 /* Craft a NEP_HANDSHAKE_FINAL message and send it to the client */
934 if( this->generate_hs_final(&pkt_out, ctx)!=OP_SUCCESS ){
935 this->nep_session_ended_handler(nsp, nse, param);
936 return OP_FAILURE;
937 }
938 nsock_write(nsp, nsi, hs_final_handler, NSOCK_INFINITE, NULL, (const char *)pkt_out.getBinaryBuffer(), pkt_out.getLen());
939 return OP_SUCCESS;
940 } /* End of nep_hs_client_handler() */
941
942
nep_hs_final_handler(nsock_pool nsp,nsock_event nse,void * param)943 int EchoServer::nep_hs_final_handler(nsock_pool nsp, nsock_event nse, void *param){
944 nping_print(DBG_4, "%s()", __func__);
945 nsock_iod nsi = nse_iod(nse);
946 nping_print(DBG_1, "SENT: NEP_HANDSHAKE_FINAL");
947 /* Receive NEP_PACKETSPEC */
948 nsock_readbytes(nsp, nsi, packetspec_handler, NSOCK_INFINITE, NULL, NEP_PACKETSPEC_LEN);
949 return OP_SUCCESS;
950 } /* End of nep_hs_final_handler() */
951
952
nep_packetspec_handler(nsock_pool nsp,nsock_event nse,void * param)953 int EchoServer::nep_packetspec_handler(nsock_pool nsp, nsock_event nse, void *param){
954 nping_print(DBG_4, "%s()", __func__);
955 nsock_iod nsi = nse_iod(nse);
956 EchoHeader pkt_in;
957 EchoHeader pkt_out;
958 NEPContext *ctx=NULL;
959 u8 *recvbuff=NULL;
960 int recvbytes=0;
961 enum nse_status status=nse_status(nse);
962 if (status!=NSE_STATUS_SUCCESS){
963 nping_print(DBG_1, "Failed to receive NEP_PACKET_SPEC message. Terminating client session\n");
964 this->nep_session_ended_handler(nsp, nse, param);
965 return OP_FAILURE;
966 }else{
967 nping_print(DBG_1, "RCVD: NEP_PACKETSPEC");
968 }
969
970 /* Lookup client context */
971 if( (ctx=this->getClientContext(nsi))==NULL ){
972 this->nep_session_ended_handler(nsp, nse, param);
973 return OP_FAILURE;
974 }
975
976 /* Ask nsock to provide received data */
977 if( (recvbuff=(u8 *)nse_readbuf(nse, &recvbytes))==NULL ){
978 this->nep_session_ended_handler(nsp, nse, param);
979 return OP_FAILURE;
980 }
981
982 /* Validate received NEP_PACKET_SPEC message */
983 if( this->parse_packet_spec(recvbuff, recvbytes, ctx)!=OP_SUCCESS ){
984 this->nep_session_ended_handler(nsp, nse, param);
985 nping_print(VB_1, "[%lu] Couldn't establish NEP session with client #%d (%s:%d).", (unsigned long)time(NULL), ctx->getIdentifier(), IPtoa(ctx->getAddress()), sockaddr2port(ctx->getAddress()));
986 return OP_FAILURE;
987 }
988 ctx->setState(STATE_READY_SENT);
989 nping_print(VB_1, "[%lu] NEP handshake with client #%d (%s:%d) was performed successfully", (unsigned long)time(NULL), ctx->getIdentifier(), IPtoa(ctx->getAddress()), sockaddr2port(ctx->getAddress()));
990
991 /* Craft response and send it */
992 this->generate_ready(&pkt_out, ctx);
993 nsock_write(nsp, nsi, ready_handler, NSOCK_INFINITE, NULL, (const char *)pkt_out.getBinaryBuffer(), pkt_out.getLen());
994
995 /* From this point, the client is not supposed to send anything to the server
996 * through the side channel. However, we now schedule a read operation so
997 * we detect when the client disconnects (because Nsock will tell us). */
998 nsock_readbytes(nsp, nsi, session_ended_handler, NSOCK_INFINITE, NULL, 65535);
999
1000 /* At this point, we consider the NEP session fully established and therefore
1001 * we update the count of served clients */
1002 o.stats.addEchoClientServed();
1003
1004 return OP_SUCCESS;
1005 } /* End of nep_packetspec_handler() */
1006
1007
nep_ready_handler(nsock_pool nsp,nsock_event nse,void * param)1008 int EchoServer::nep_ready_handler(nsock_pool nsp, nsock_event nse, void *param){
1009 nping_print(DBG_4, "%s()", __func__);
1010 nping_print(DBG_1, "SENT: NEP_READY");
1011 return OP_SUCCESS;
1012 } /* End of nep_ready_handler() */
1013
1014
nep_session_ended_handler(nsock_pool nsp,nsock_event nse,void * param)1015 int EchoServer::nep_session_ended_handler(nsock_pool nsp, nsock_event nse, void *param){
1016 nping_print(DBG_4, "%s()", __func__);
1017 nsock_iod nsi = nse_iod(nse);
1018 clientid_t clnt;
1019 NEPContext *ctx=NULL;
1020
1021 /* Lookup client context */
1022 if( (ctx=this->getClientContext(nsi))!=NULL ){
1023 nping_print(VB_0, "[%lu] Client #%d (%s:%d) disconnected", (unsigned long)time(NULL), ctx->getIdentifier(), IPtoa(ctx->getAddress()), sockaddr2port(ctx->getAddress()));
1024 clnt=ctx->getIdentifier();
1025 if(this->destroyClientContext(clnt)!=OP_SUCCESS)
1026 nping_print(DBG_2, "Client #%d disconnected but no context found. This may be a bug.", clnt);
1027 else
1028 nping_print(DBG_2, "Deleted client #%d context.", clnt);
1029 }
1030 nsock_iod_delete(nsi, NSOCK_PENDING_SILENT);
1031
1032 /* Exit the server if --once has been set */
1033 if(o.once()){
1034 o.displayStatistics();
1035 o.displayNpingDoneMsg();
1036 o.cleanup();
1037 exit(EXIT_SUCCESS);
1038 }
1039 return OP_SUCCESS;
1040 } /* End of nep_session_ended_handler() */
1041
1042
1043
1044 /** Processes and validates a received NEP_HANDSHAKE_CLIENT message. On success
1045 * it returns OP_SUCCESS. OP_FAILURE is returned in case the received packet
1046 * is not valid. */
parse_hs_client(u8 * pkt,size_t pktlen,NEPContext * ctx)1047 int EchoServer::parse_hs_client(u8 *pkt, size_t pktlen, NEPContext *ctx){
1048 nping_print(DBG_4, "%s()", __func__);
1049 u8 *next_iv=NULL;
1050 EchoHeader h;
1051 if(pkt==NULL || ctx==NULL){
1052 nping_print(DBG_1,"%s(): NULL parameter supplied.", __func__ );
1053 return OP_FAILURE;
1054 }
1055 if(pktlen!=NEP_HANDSHAKE_CLIENT_LEN){
1056 nping_print(DBG_1,"%s(): Unexpected length supplied.", __func__ );
1057 return OP_FAILURE;
1058 }
1059 h.storeRecvData(pkt, pktlen);
1060
1061 /* Validate version number */
1062 if( h.getVersion() != ECHO_CURRENT_PROTO_VER ){
1063 nping_print(DBG_1, "Expected NEP version %02x but message used %02x", ECHO_CURRENT_PROTO_VER, h.getVersion() );
1064 return OP_FAILURE;
1065 }
1066
1067 /* Ensure the expected message type was received */
1068 if(h.getMessageType()!=TYPE_NEP_HANDSHAKE_CLIENT){
1069 nping_print(DBG_1, "Expected NEP_HANDSHAKE_CLIENT but received %02X", h.getMessageType() );
1070 return OP_FAILURE;
1071 }
1072
1073 /* Ensure the received timestamp falls into the allowed time window */
1074 //if( h.verifyTimestamp()!=OP_SUCCESS ){
1075 // nping_print(DBG_1, "NEP_HANDSHAKE_CLIENT timestamp is too old", h.getMessageType() );
1076 // return OP_FAILURE;
1077 //}
1078
1079 /* Ensure message length is correct */
1080 if( h.getTotalLength()!=(NEP_HANDSHAKE_CLIENT_LEN/4)){
1081 nping_print(DBG_1, "Received NEP_HANDSHAKE_CLIENT specifies an incorrect length (%u)", h.getTotalLength()*4 );
1082 return OP_FAILURE;
1083 }
1084
1085 /* Ensure the client echoed the nonce we sent in our NEP_HANDSHAKE_SERVER */
1086 if( memcmp(h.getServerNonce(), ctx->getServerNonce(), NONCE_LEN)!=0 ){
1087 nping_print(DBG_1, "Echoed nonce in NEP_HANDSHAKE_CLIENT message does not match client generate nonce");
1088 return OP_FAILURE;
1089 }
1090 /* Store the received nonce */
1091 ctx->setClientNonce(h.getClientNonce());
1092
1093 /* Store client's sequence number */
1094 ctx->setLastClientSequence( h.getSequenceNumber() );
1095
1096 /* Generate all session keys */
1097 ctx->generateCipherKeyC2S();
1098 ctx->generateCipherKeyS2C();
1099 ctx->generateMacKeyC2S();
1100 ctx->generateMacKeyS2C();
1101
1102 nping_print(DBG_3,"Session Key MAC_C2S:"); print_hexdump(DBG_3,ctx->getMacKeyC2S(), MAC_KEY_LEN);
1103 nping_print(DBG_3,"Session Key MAC_S2C:"); print_hexdump(DBG_3,ctx->getMacKeyS2C(), MAC_KEY_LEN);
1104 nping_print(DBG_3,"Session Key CIPHER_C2S:"); print_hexdump(DBG_3,ctx->getCipherKeyC2S(), MAC_KEY_LEN);
1105 nping_print(DBG_3,"Session Key CIPHER_S2C:"); print_hexdump(DBG_3,ctx->getCipherKeyS2C(), MAC_KEY_LEN);
1106
1107
1108 /* Decrypt the encrypted part of the message before validating the MAC */
1109 if((next_iv=h.decrypt(ctx->getCipherKeyC2S(), CIPHER_KEY_LEN, ctx->getClientNonce(), TYPE_NEP_HANDSHAKE_CLIENT))==NULL){
1110 nping_print(DBG_1, "Failed to decrypt NEP_HANDSHAKE_CLIENT data." );
1111 return OP_FAILURE;
1112 }
1113 ctx->setNextDecryptionIV(next_iv);
1114
1115 /* Check the authenticity of the received message */
1116 if( h.verifyMessageAuthenticationCode( ctx->getMacKeyC2S(), MAC_KEY_LEN)!=OP_SUCCESS ){
1117 nping_print(DBG_1, "NEP_HANDSHAKE_CLIENT authentication failed" );
1118 return OP_FAILURE;
1119 }
1120
1121 return OP_SUCCESS;
1122 } /* End of parse_hs_client() */
1123
1124
1125 /** Processes and validates a received NEP_PACKET_SPEC message. On success
1126 * it returns OP_SUCCESS. OP_FAILURE is returned in case the received packet
1127 * is not valid. */
parse_packet_spec(u8 * pkt,size_t pktlen,NEPContext * ctx)1128 int EchoServer::parse_packet_spec(u8 *pkt, size_t pktlen, NEPContext *ctx){
1129 nping_print(DBG_4, "%s()", __func__);
1130 EchoHeader h;
1131 int recvspecs=0;
1132 bool id_received=false;
1133 u8 field=0;
1134 size_t len=0;
1135 u8 *next_iv=NULL;
1136 u8 specbuff[PACKETSPEC_FIELD_LEN];
1137 if(pkt==NULL){
1138 nping_print(DBG_1,"%s(): NULL parameter supplied.", __func__ );
1139 return OP_FAILURE;
1140 }
1141 if(pktlen!=NEP_PACKETSPEC_LEN){
1142 nping_print(DBG_1,"%s(): Unexpected length supplied.", __func__ );
1143 return OP_FAILURE;
1144 }
1145 h.storeRecvData(pkt, pktlen);
1146
1147 /* Decrypt message */
1148 if((next_iv=h.decrypt(ctx->getCipherKeyC2S(), CIPHER_KEY_LEN, ctx->getNextDecryptionIV(), TYPE_NEP_PACKET_SPEC))==NULL){
1149 nping_print(DBG_1, "Failed to decrypt NEP_PACKET_SPEC data." );
1150 return OP_FAILURE;
1151 }
1152 ctx->setNextDecryptionIV(next_iv);
1153
1154 /* Validate version number */
1155 if( h.getVersion() != ECHO_CURRENT_PROTO_VER ){
1156 nping_print(DBG_1, "Expected NEP version %02x but message used %02x", ECHO_CURRENT_PROTO_VER, h.getVersion() );
1157 return OP_FAILURE;
1158 }
1159
1160 /* Ensure the expected message type was received */
1161 if(h.getMessageType()!=TYPE_NEP_PACKET_SPEC){
1162 nping_print(DBG_1, "Expected NEP_PACKET_SPEC but received %02X", h.getMessageType() );
1163 return OP_FAILURE;
1164 }
1165
1166 /* Ensure the received timestamp falls into the allowed time window */
1167 //if( h.verifyTimestamp()!=OP_SUCCESS ){
1168 // nping_print(DBG_1, "NEP_PACKET_SPEC timestamp is too old", h.getMessageType() );
1169 // return OP_FAILURE;
1170 //}
1171
1172 /* Ensure message length is correct */
1173 if( h.getTotalLength()!=(NEP_PACKETSPEC_LEN/4)){
1174 nping_print(DBG_1, "Received NEP_PACKET_SPEC specifies an incorrect length (%u)", h.getTotalLength()*4 );
1175 return OP_FAILURE;
1176 }
1177
1178 /* Ensure the received sequence number is the previous+1 */
1179 if( h.getSequenceNumber()!=(ctx->getLastClientSequence()+1)){
1180 nping_print(DBG_1, "Expected sequence number %d but received %d", ctx->getLastClientSequence()+1, h.getSequenceNumber() );
1181 return OP_FAILURE;
1182 }else{
1183 /* Increment next expected sequence number*/
1184 ctx->getNextClientSequence();
1185 }
1186
1187 /* Check the authenticity of the received message */
1188 if( h.verifyMessageAuthenticationCode( ctx->getMacKeyC2S(), MAC_KEY_LEN)!=OP_SUCCESS ){
1189 nping_print(DBG_1, "NEP_PACKET_SPEC authentication failed" );
1190 return OP_FAILURE;
1191 }
1192
1193 /* Now that we have verified the authenticity of the message, let's process
1194 * the field specifiers */
1195 while(1){
1196 if( h.getNextFieldSpec(&field, specbuff, &len)==OP_FAILURE ){
1197 break;
1198 }else{
1199
1200 /* Ensure the field spec is unique. Malicious users could try to supply
1201 * the same spec more than once in order to get higher packet scores. */
1202 if( ctx->isDuplicateFieldSpec(field) ){
1203 nping_print(DBG_1, "Detected duplicate field specs in NEP_PACKET_SPEC message" );
1204 return OP_FAILURE;
1205 }else{
1206 ctx->addClientFieldSpec(field, len, specbuff);
1207 recvspecs++;
1208 }
1209 /* Set a flag to indicate that mandatory IPv4 ID or IPv6 Flow has been
1210 * supplied by the client */
1211 if(h.getIPVersion()==0x04 && field==PSPEC_IPv4_ID)
1212 id_received=true;
1213 else if(h.getIPVersion()==0x06 && field==PSPEC_IPv6_FLOW)
1214 id_received=true;
1215 nping_print(DBG_3|NO_NEWLINE,"RCVD FieldSpec: Type=%02X Len=%02x Data=0x", field, (u8)len);
1216 for(unsigned int i=0; i<len; i++)
1217 nping_print(DBG_3|NO_NEWLINE,"%02x", specbuff[i]);
1218 nping_print(DBG_3, ";");
1219 }
1220 }
1221 /* Check client provided mandatory IP ID (or Flow) spec and at least one other spec */
1222 if(id_received && recvspecs>=4){
1223 nping_print(VB_2, "[%lu] Good packet specification received from client #%d (Specs=%d,IP=%d,Proto=%d,Cnt=%d)",
1224 (unsigned long)time(NULL), ctx->getIdentifier(), recvspecs, h.getIPVersion(), h.getProtocol(), h.getPacketCount()
1225 );
1226 return OP_SUCCESS;
1227 }else{
1228 return OP_FAILURE;
1229 }
1230 } /* End of parse_packet_spec() */
1231
1232
1233 /** Generates a NEP_HANDSHAKE_SERVER message. On success it returns OP_SUCCESS.
1234 * OP_FAILURE is returned in case of error.
1235 * @warning the caller must ensure that the supplied context object
1236 * already contains an initial sequence number and a server nonce. */
generate_hs_server(EchoHeader * h,NEPContext * ctx)1237 int EchoServer::generate_hs_server(EchoHeader *h, NEPContext *ctx){
1238 nping_print(DBG_4, "%s()", __func__);
1239 if(h==NULL || ctx==NULL)
1240 return OP_FAILURE;
1241
1242 /* Craft NEP_HANDSHAKE_SERVER message */
1243 h->setMessageType(TYPE_NEP_HANDSHAKE_SERVER);
1244 h->setSequenceNumber( ctx->getLastServerSequence() );
1245 h->setTimestamp();
1246 h->setServerNonce( ctx->getServerNonce() );
1247 h->setTotalLength();
1248 h->setMessageAuthenticationCode( ctx->getMacKeyS2C(), MAC_KEY_LEN);
1249 return OP_SUCCESS;
1250 } /* End of generate_hs_server() */
1251
1252
1253 /** Generates a NEP_HANDSHAKE_FINAL message. On success it returns OP_SUCCESS.
1254 * OP_FAILURE is returned in case of error. */
generate_hs_final(EchoHeader * h,NEPContext * ctx)1255 int EchoServer::generate_hs_final(EchoHeader *h, NEPContext *ctx){
1256 nping_print(DBG_4, "%s()", __func__);
1257 struct sockaddr_storage ss;
1258 u8 *next_iv=NULL;
1259 if(h==NULL || ctx==NULL)
1260 return OP_FAILURE;
1261
1262 /* Craft NEP_HANDSHAKE_CLIENT message */
1263 h->setMessageType(TYPE_NEP_HANDSHAKE_FINAL);
1264 h->setSequenceNumber(ctx->getNextServerSequence() );
1265 h->setTimestamp();
1266 h->setClientNonce( ctx->getClientNonce() );
1267 ss=ctx->getAddress();
1268 if(ss.ss_family==AF_INET6){
1269 struct sockaddr_in6 *s6=(struct sockaddr_in6 *)&ss;
1270 h->setPartnerAddress(s6->sin6_addr);
1271 }else{
1272 struct sockaddr_in *s4=(struct sockaddr_in *)&ss;
1273 h->setPartnerAddress(s4->sin_addr);
1274 }
1275 h->setTotalLength();
1276 h->setMessageAuthenticationCode( ctx->getMacKeyS2C(), MAC_KEY_LEN);
1277
1278 /* Encrypt message */
1279 if( (next_iv=h->encrypt(ctx->getCipherKeyS2C(), CIPHER_KEY_LEN, ctx->getServerNonce()))==NULL )
1280 return OP_FAILURE;
1281 ctx->setNextEncryptionIV(next_iv);
1282
1283
1284 return OP_SUCCESS;
1285 } /* End of generate_hs_final() */
1286
1287
1288 /** Generates a NEP_READY message. On success it returns OP_SUCCESS.
1289 * OP_FAILURE is returned in case of error. */
generate_ready(EchoHeader * h,NEPContext * ctx)1290 int EchoServer::generate_ready(EchoHeader *h, NEPContext *ctx){
1291 nping_print(DBG_4, "%s()", __func__);
1292 u8 *next_iv=NULL;
1293 if(h==NULL || ctx==NULL)
1294 return OP_FAILURE;
1295
1296 /* Craft NEP_READY message */
1297 h->setMessageType(TYPE_NEP_READY);
1298 h->setSequenceNumber( ctx->getNextServerSequence() );
1299 h->setTimestamp();
1300 h->setTotalLength();
1301 h->setMessageAuthenticationCode(ctx->getMacKeyS2C(), MAC_KEY_LEN);
1302
1303 /* Encrypt message */
1304 if( (next_iv=h->encrypt(ctx->getCipherKeyS2C(), CIPHER_KEY_LEN, ctx->getNextEncryptionIV()))==NULL )
1305 return OP_FAILURE;
1306 ctx->setNextEncryptionIV(next_iv);
1307
1308 return OP_SUCCESS;
1309 } /* End of generate_ready() */
1310
1311
1312 /** Generates a NEP_ECHO message. On success it returns OP_SUCCESS.
1313 * OP_FAILURE is returned in case of error. */
generate_echo(EchoHeader * h,const u8 * pkt,size_t pktlen,NEPContext * ctx)1314 int EchoServer::generate_echo(EchoHeader *h, const u8 *pkt, size_t pktlen, NEPContext *ctx){
1315 nping_print(DBG_4, "%s()", __func__);
1316 u8 *next_iv=NULL;
1317 if(h==NULL || ctx==NULL || pkt==NULL || pktlen==0)
1318 return OP_FAILURE;
1319
1320 /* Craft NEP_ECHO message */
1321 h->setMessageType(TYPE_NEP_ECHO);
1322 h->setSequenceNumber( ctx->getNextServerSequence() );
1323 h->setTimestamp();
1324 h->setDLT(DLT_NODATALINKHEADERINCLUDED);
1325
1326 /* If allowed, echo the whole packet, including any application layer data */
1327 if( o.echoPayload() ){
1328 h->setEchoedPacket(pkt, pktlen);
1329 /* Otherwise, find if the packet contains application layer data and erase it */
1330 }else{
1331 /* Determine where the application data starts */
1332 int offset=PacketParser::payload_offset(pkt, pktlen, false);
1333
1334 /* If the packet does not have application data, don't touch it */
1335 if(offset==0){
1336 nping_print(DBG_3, "No payload found. Echoing the whole packet\n");
1337 h->setEchoedPacket(pkt, pktlen);
1338 /* If we found application data, zero it */
1339 }else{
1340 nping_print(DBG_3, "Erasing %d payload bytes\n", (int)pktlen-offset);
1341 /* Allocate a new buffer, big enough to hold the packet */
1342 u8 *new_pkt=(u8 *)safe_zalloc(pktlen);
1343 /* Copy the initial header, and leave the rest as 0x00 bytes */
1344 if(offset>0 && offset<(int)pktlen){
1345 memcpy(new_pkt, pkt, offset);
1346 /* If there was some error trying to find application data, include a
1347 * default amount of data */
1348 }else{
1349 memcpy(new_pkt, pkt, MIN(pktlen, PAYLOAD_ECHO_BYTES_IN_DOUBT));
1350 }
1351 h->setEchoedPacket(new_pkt, pktlen);
1352 free(new_pkt);
1353 }
1354 }
1355
1356 h->setTotalLength();
1357 h->setMessageAuthenticationCode(ctx->getMacKeyS2C(), MAC_KEY_LEN);
1358
1359 if( (next_iv=h->encrypt(ctx->getCipherKeyS2C(), CIPHER_KEY_LEN, ctx->getNextEncryptionIV()))==NULL )
1360 return OP_FAILURE;
1361 ctx->setNextEncryptionIV(next_iv);
1362
1363 return OP_SUCCESS;
1364 } /* End of generate_echo() */
1365
1366
1367 /** This is the server's main method. It sets up nsock and pcap, waits for
1368 * client connections and handles all the events of the client sessions. */
start()1369 int EchoServer::start() {
1370 nping_print(DBG_4, "%s()", __func__);
1371 nsock_pool nsp; /**< Nsock pool */
1372 enum nsock_loopstatus loopret; /**< Stores nsock_loop returned status */
1373 nsock_iod client_nsi; /**< Stores connected client IOD */
1374 nsock_iod pcap_nsi; /**< Stores Pcap IOD */
1375 char pcapdev[128]; /**< Device name passed to pcap_open_live */
1376 struct timeval now; /**< For timestamps */
1377 struct sockaddr_storage ss; /**< New client socket address */
1378 socklen_t sslen=sizeof(ss); /**< New client socket address len */
1379 int listen_sd=-1; /**< Socket descriptor for listening */
1380 int client_sd=-1; /**< Socket descriptor for new clients */
1381 clientid_t *idpnt=NULL; /**< For new client assigned identifiers */
1382 NEPContext ctx; /**< Context for the new client */
1383 EchoHeader h;
1384 int rc;
1385
1386 /* Create a new nsock pool */
1387 if ((nsp = nsock_pool_new(NULL)) == NULL)
1388 nping_fatal(QT_3, "Failed to create new pool. QUITTING.\n");
1389
1390 /* Set nsock trace level */
1391 gettimeofday(&now, NULL);
1392 if( o.getDebugging() == DBG_5 )
1393 nsock_set_loglevel(NSOCK_LOG_INFO);
1394 else if( o.getDebugging() > DBG_5 )
1395 nsock_set_loglevel(NSOCK_LOG_DBG_ALL);
1396
1397 /* Create new IOD for pcap */
1398 if ((pcap_nsi = nsock_iod_new(nsp, NULL)) == NULL)
1399 nping_fatal(QT_3, "Failed to create new nsock_iod. QUITTING.\n");
1400
1401 /* Open pcap */
1402 nping_print(DBG_2,"Opening pcap device %s", o.getDevice());
1403 Strncpy(pcapdev, o.getDevice(), sizeof(pcapdev));
1404 rc = nsock_pcap_open(nsp, pcap_nsi, pcapdev, MAX_ECHOED_PACKET_LEN, 1,
1405 ProbeMode::getBPFFilterString());
1406 if (rc)
1407 nping_fatal(QT_3, "Error opening capture device %s\n", o.getDevice());
1408 else
1409 nping_print(VB_0,"Packet capture will be performed using network interface %s.", o.getDevice());
1410 nping_print(VB_0,"Waiting for connections...");
1411
1412 /* Get a socket suitable for an accept() call */
1413 listen_sd=this->nep_listen_socket();
1414
1415 while(1){
1416 /* If --once is enabled, just allow the first client */
1417 if(o.once()==false || this->client_id_count==-1){
1418 /* Check if we have received a connection*/
1419 unblock_socket(listen_sd);
1420 if ((client_sd=accept(listen_sd, (struct sockaddr *)&ss, &sslen)) >= 0){
1421 nping_print(VB_0, "[%lu] Connection received from %s:%d", (unsigned long)time(NULL), IPtoa(&ss), sockaddr2port(&ss));
1422 /* Assign a new client identifier. The ID is bound to the IOD */
1423 if( (idpnt=(clientid_t *)calloc(1, sizeof(clientid_t)))==NULL ){
1424 nping_warning(QT_2, "Not enough memory for new clients.");
1425 return OP_FAILURE;
1426 }
1427 *idpnt=this->getNewClientID();
1428 if( (client_nsi=nsock_iod_new2(nsp, client_sd, idpnt))==NULL ){
1429 nping_warning(QT_2, "Not enough memory for new clients.");
1430 return OP_FAILURE;
1431 }else{
1432 close(client_sd); /* nsock_iod_new2() dups the socket */
1433 }
1434
1435 /* Stop listening if --once is enabled */
1436 if(o.once()==true)
1437 close(listen_sd);
1438
1439 /* Create a new client context object */
1440 ctx.setIdentifier(*idpnt);
1441 ctx.setAddress(ss);
1442 ctx.setNsockIOD(client_nsi);
1443 ctx.generateServerNonce();
1444 ctx.generateInitialServerSequence();
1445 ctx.generateMacKeyS2CInitial();
1446 nping_print(DBG_3,"Session Key MAC_S2C_INITIAL:"); print_hexdump(DBG_3,ctx.getMacKeyS2C(), MAC_KEY_LEN);
1447
1448 /* Craft NEP_HANDSHAKE_SERVER message */
1449 if( this->generate_hs_server(&h, &ctx)!=OP_SUCCESS)
1450 return OP_FAILURE;
1451 else
1452 this->addClientContext(ctx);
1453
1454 /* Schedule send operation */
1455 nsock_write(nsp, client_nsi, hs_server_handler, NSOCK_INFINITE, NULL, (const char *)h.getBufferPointer(), h.getLen() );
1456
1457 /* For every client we schedule a packet capture event. */
1458 nsock_pcap_read_packet(nsp, pcap_nsi, capture_handler, NSOCK_INFINITE, NULL);
1459
1460 }
1461 block_socket(listen_sd);
1462 }
1463 /* Sleep for a second until we check again for incoming connection requests */
1464 nsock_timer_create(nsp, empty_handler, 1000, NULL);
1465 loopret=nsock_loop(nsp, 1000);
1466 //If something went wrong in nsock_loop, let's just bail out.
1467 if (loopret == NSOCK_LOOP_ERROR) {
1468 nping_warning(QT_3, "Unexpected nsock_loop error.\n");
1469 return OP_FAILURE;
1470 }
1471 }
1472 return OP_SUCCESS;
1473 } /* End of start() */
1474
1475
1476 /** Performs cleanup functions */
cleanup()1477 int EchoServer::cleanup(){
1478 // For the moment there is nothing to cleanup
1479 return OP_SUCCESS;
1480 } /* End of cleanup() */
1481
1482 /******************************************************************************/
1483 /**** HANDLER WRAPPERS ********************************************************/
1484 /******************************************************************************/
1485
1486 /* This handler is a wrapper for the EchoServer::nep_read_handler() method. We
1487 * need this because C++ does not allow to use class methods as callback
1488 * functions for things like signal() or the Nsock lib. */
capture_handler(nsock_pool nsp,nsock_event nse,void * arg)1489 void capture_handler(nsock_pool nsp, nsock_event nse, void *arg){
1490 nping_print(DBG_4, "%s()", __func__);
1491 es.nep_capture_handler(nsp, nse, arg);
1492 return;
1493 } /* End of capture_handler() */
1494
1495
1496 /* This handler is a wrapper for the EchoServer::nep_echo_handler() method. We
1497 * need this because C++ does not allow to use class methods as callback
1498 * functions for things like signal() or the Nsock lib. */
echo_handler(nsock_pool nsp,nsock_event nse,void * arg)1499 void echo_handler(nsock_pool nsp, nsock_event nse, void *arg){
1500 nping_print(DBG_4, "%s()", __func__);
1501 es.nep_echo_handler(nsp, nse, arg);
1502 return;
1503 } /* End of echo_handler() */
1504
1505
1506 /* This handler is a wrapper for the EchoServer::nep_hs_server_handler() method. We
1507 * need this because C++ does not allow to use class methods as callback
1508 * functions for things like signal() or the Nsock lib. */
hs_server_handler(nsock_pool nsp,nsock_event nse,void * arg)1509 void hs_server_handler(nsock_pool nsp, nsock_event nse, void *arg){
1510 nping_print(DBG_4, "%s()", __func__);
1511 es.nep_hs_server_handler(nsp, nse, arg);
1512 return;
1513 } /* End of hs_server_handler() */
1514
1515
1516 /* This handler is a wrapper for the EchoServer::nep_hs_client_handler() method. We
1517 * need this because C++ does not allow to use class methods as callback
1518 * functions for things like signal() or the Nsock lib. */
hs_client_handler(nsock_pool nsp,nsock_event nse,void * arg)1519 void hs_client_handler(nsock_pool nsp, nsock_event nse, void *arg){
1520 nping_print(DBG_4, "%s()", __func__);
1521 es.nep_hs_client_handler(nsp, nse, arg);
1522 return;
1523 } /* End of hs_client_handler() */
1524
1525
1526 /* This handler is a wrapper for the EchoServer::nep_hs_final_handler() method. We
1527 * need this because C++ does not allow to use class methods as callback
1528 * functions for things like signal() or the Nsock lib. */
hs_final_handler(nsock_pool nsp,nsock_event nse,void * arg)1529 void hs_final_handler(nsock_pool nsp, nsock_event nse, void *arg){
1530 nping_print(DBG_4, "%s()", __func__);
1531 es.nep_hs_final_handler(nsp, nse, arg);
1532 return;
1533 } /* End of hs_final_handler() */
1534
1535
1536 /* This handler is a wrapper for the EchoServer::nep_packetspec_handler() method. We
1537 * need this because C++ does not allow to use class methods as callback
1538 * functions for things like signal() or the Nsock lib. */
packetspec_handler(nsock_pool nsp,nsock_event nse,void * arg)1539 void packetspec_handler(nsock_pool nsp, nsock_event nse, void *arg){
1540 nping_print(DBG_4, "%s()", __func__);
1541 es.nep_packetspec_handler(nsp, nse, arg);
1542 return;
1543 } /* End of packetspec_handler() */
1544
1545
1546 /* This handler is a wrapper for the EchoServer::nep_ready_handler() method. We
1547 * need this because C++ does not allow to use class methods as callback
1548 * functions for things like signal() or the Nsock lib. */
ready_handler(nsock_pool nsp,nsock_event nse,void * arg)1549 void ready_handler(nsock_pool nsp, nsock_event nse, void *arg){
1550 nping_print(DBG_4, "%s()", __func__);
1551 es.nep_ready_handler(nsp, nse, arg);
1552 return;
1553 } /* End of ready_handler() */
1554
1555
1556 /* This handler is a wrapper for the EchoServer::nep_ready_handler() method. We
1557 * need this because C++ does not allow to use class methods as callback
1558 * functions for things like signal() or the Nsock lib. */
session_ended_handler(nsock_pool nsp,nsock_event nse,void * arg)1559 void session_ended_handler(nsock_pool nsp, nsock_event nse, void *arg){
1560 nping_print(DBG_4, "%s()", __func__);
1561 es.nep_session_ended_handler(nsp, nse, arg);
1562 return;
1563 } /* End of ready_handler() */
1564
1565
1566 /* Void handler that does nothing */
empty_handler(nsock_pool nsp,nsock_event nse,void * arg)1567 void empty_handler(nsock_pool nsp, nsock_event nse, void *arg){
1568 return;
1569 } /* End of capture_handler() */
1570