forked from nmap/nmap
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathnse_nsock.cc
1411 lines (1179 loc) · 40.1 KB
/
nse_nsock.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#include "nse_nsock.h"
#include "nse_auxiliar.h"
#include "nse_macros.h"
#include "nse_string.h"
#include "nse_debug.h"
#include "nsock.h"
#include "nmap_error.h"
/* #include "osscan.h" */
#include "NmapOps.h"
#include <stdio.h>
#include <stdlib.h>
#include <errno.h>
#include "utils.h"
#include "tcpip.h"
#if HAVE_OPENSSL
#include <openssl/ssl.h>
#endif
#define SCRIPT_ENGINE "SCRIPT ENGINE"
#define NSOCK_WRAPPER "NSOCK WRAPPER"
#define NSOCK_WRAPPER_SUCCESS 0
#define NSOCK_WRAPPER_ERROR 2
#define NSOCK_WRAPPER_BUFFER_OK 1
#define NSOCK_WRAPPER_BUFFER_MOREREAD 2
#define FROM 1
#define TO 2
#define DEFAULT_TIMEOUT 30000
extern NmapOps o;
// defined in nse_main.cc but also declared here
// to keep the .h files clean
int process_waiting2running(lua_State* l, int resume_arguments);
static int l_nsock_connect(lua_State* l);
static int l_nsock_connect_queued(lua_State* l);
static int l_nsock_send(lua_State* l);
static int l_nsock_receive(lua_State* l);
static int l_nsock_receive_lines(lua_State* l);
static int l_nsock_receive_bytes(lua_State* l);
static int l_nsock_get_info(lua_State* l);
static int l_nsock_gc(lua_State* l);
static int l_nsock_close(lua_State* l);
static int l_nsock_set_timeout(lua_State* l);
static int l_nsock_receive_buf(lua_State* l);
static int l_nsock_ncap_open(lua_State* l);
static int l_nsock_ncap_close(lua_State* l);
static int l_nsock_ncap_register(lua_State *l);
static int l_nsock_pcap_receive(lua_State* l);
void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *lua_state);
void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *lua_state);
void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state);
void l_nsock_receive_buf_handler(nsock_pool nsp, nsock_event nse, void *lua_state);
int l_nsock_check_buf(lua_State* l);
int l_nsock_checkstatus(lua_State* l, nsock_event nse);
void l_nsock_trace(nsock_iod nsiod, const char* message, int direction);
const char* inet_ntop_both(int af, const void* v_addr, char* ipstring);
unsigned short inet_port_both(int af, const void* v_addr);
static luaL_reg l_nsock [] = {
{"connect", l_nsock_connect_queued},
{"send", l_nsock_send},
{"receive", l_nsock_receive},
{"receive_lines", l_nsock_receive_lines},
{"receive_bytes", l_nsock_receive_bytes},
{"receive_buf", l_nsock_receive_buf},
{"get_info", l_nsock_get_info},
{"close", l_nsock_close},
{"set_timeout", l_nsock_set_timeout},
{"__gc",l_nsock_gc},
{"pcap_open", l_nsock_ncap_open},
{"pcap_close", l_nsock_ncap_close},
{"pcap_register", l_nsock_ncap_register},
{"pcap_receive", l_nsock_pcap_receive},
// {"callback_test", l_nsock_pcap_callback_test},
{NULL, NULL}
};
static nsock_pool nsp;
/* There can't be more opened descriptors than max_descriptors_allowed
* (search below) If there are no more free slots, lua thread is
* freezed and saved to nsock_connect_queue. It's restored when when a
* descriptor becomes availble (after nsock_close). */
static int nsock_descriptors_used; /* nsock descriptors currently in use */
std::list<lua_State* > nsock_connect_queue; /* list of freezed threads waiting for desc */
/*
* Structure with nsock pcap descriptor.
* shared between many lua threads
*/
struct ncap_socket{
nsock_iod nsiod; /* nsock pcap desc */
int references; /* how many lua threads use this */
char *key; /* (free) zero-terminated key used in map to
* address this structure. */
};
/*
*
*/
struct ncap_request{
int suspended; /* is the thread suspended? (lua_yield) */
lua_State *l; /* lua_State of current process
* or NULL if process isn't suspended */
nsock_event_id nseid; /* nse for this specific lua_State */
struct timeval end_time;
char *key; /* (free) zero-terminated key used in map to
* address this structure (hexified 'test') */
bool received; /* are results ready? */
bool r_success; /* true-> okay,data ready to pass to user
* flase-> this statusstring contains error description */
char * r_status; /* errorstring */
unsigned char *r_layer2;
size_t r_layer2_len;
unsigned char *r_layer3;
size_t r_layer3_len;
size_t packetsz;
int ncap_cback_ref; /* just copy of udata->ncap_cback_ref
* because we don't have access to udata in place
* we need to use this. */
};
struct l_nsock_udata {
int timeout;
nsock_iod nsiod;
void *ssl_session;
/*used for buffered reading */
int bufidx; /*index inside lua's registry */
int bufused;
struct ncap_socket *ncap_socket;
struct ncap_request *ncap_request;
int ncap_cback_ref;
};
void l_nsock_clear_buf(lua_State* l, l_nsock_udata* udata);
int l_nsock_open(lua_State* l) {
auxiliar_newclass(l, "nsock", l_nsock);
nsp = nsp_new(NULL);
//nsp_settrace(nsp, o.debugging, o.getStartTime());
if (o.scriptTrace())
nsp_settrace(nsp, 5, o.getStartTime());
return NSOCK_WRAPPER_SUCCESS;
}
int l_nsock_new(lua_State* l) {
struct l_nsock_udata* udata;
udata = (struct l_nsock_udata*) lua_newuserdata(l, sizeof(struct l_nsock_udata));
auxiliar_setclass(l, "nsock", -1);
udata->nsiod = NULL;
udata->ssl_session = NULL;
udata->timeout = DEFAULT_TIMEOUT;
udata->bufidx = LUA_NOREF;
udata->bufused= 0;
udata->ncap_socket = NULL;
udata->ncap_request = NULL;
udata->ncap_cback_ref = 0;
return 1;
}
int l_nsock_loop(int tout) {
return nsock_loop(nsp, tout);
}
int l_nsock_checkstatus(lua_State* l, nsock_event nse) {
enum nse_status status = nse_status(nse);
switch (status) {
case NSE_STATUS_SUCCESS:
lua_pushboolean(l, true);
return NSOCK_WRAPPER_SUCCESS;
break;
case NSE_STATUS_ERROR:
case NSE_STATUS_TIMEOUT:
case NSE_STATUS_CANCELLED:
case NSE_STATUS_KILL:
case NSE_STATUS_EOF:
lua_pushnil(l);
lua_pushstring(l, nse_status2str(status));
return NSOCK_WRAPPER_ERROR;
break;
case NSE_STATUS_NONE:
default:
fatal("%s: In: %s:%i This should never happen.",
NSOCK_WRAPPER, __FILE__, __LINE__);
break;
}
return -1;
}
static int l_nsock_connect_queued(lua_State* l) {
/* We allow at least 10 even max_parallelism is 1 because a single
script might open a few sockets at once and we don't want it to
deadlock when it tries to open the 2nd one. */
const int max_descriptors_allowed = MAX(o.max_parallelism, 10);
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
if(udata->nsiod!=NULL){
/*should a script try to connect a socket, which is already connected
* we close the old connection, since it would have no access to it
* anyways
*/
if(o.scriptTrace()){
log_write(LOG_STDOUT,"%s: Trying to connect already connected socket - closing!\n",SCRIPT_ENGINE);
}
l_nsock_close(l);
lua_pop(l,1);
}
if(nsock_descriptors_used >= max_descriptors_allowed){
/* wait for free descriptor */
nsock_connect_queue.push_back(l);
/* I must know how many arguments are passed to nsock_connect.
* is there a better way? */
int arguments = 3;
const char *how = luaL_optstring(l, 4, "");
if(*how != '\0'){
arguments = 4;
int port = luaL_optinteger(l, 5, -1);
if(port!=-1)
arguments = 5;
}
if(o.scriptTrace())
log_write(LOG_STDOUT, "NSOCK_connect_queued: thread queued (%i args) %p\n", arguments, (void *)l);
return lua_yield(l, arguments);
}
return l_nsock_connect(l);
}
void l_nsock_connect_queued_handler(nsock_pool nsp, nsock_event nse, void *lua_state) {
lua_State* l = (lua_State*) lua_state;
/* well, this is really hackish, we can't just do process_waiting2running, because
* nsock_connect() can do lua_yield().
* Instead, we first execute nsock_connect, and if it returns lua_yield() (ie. -1)
* than we don't do process_waiting2running.
* So, in summary we can do two lua_yield() on thread (one in l_nsock_connect_queued,
* second in l_nsock_connect). But it works for me. */
int r = l_nsock_connect(l);
if(r != -1)
process_waiting2running((lua_State*) lua_state, 0);
}
static int l_nsock_connect(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
const char* addr = luaL_checkstring(l, 2);
unsigned short port = (unsigned short) luaL_checkint(l, 3);
const char *how = luaL_optstring(l, 4, "tcp");
const char* error;
struct addrinfo *dest;
int error_id;
l_nsock_clear_buf(l, udata);
error_id = getaddrinfo(addr, NULL, NULL, &dest);
if (error_id) {
error = gai_strerror(error_id);
lua_pushboolean(l, false);
lua_pushstring(l, error);
return 2;
}
udata->nsiod = nsi_new(nsp, NULL);
nsock_descriptors_used++;
switch (how[0]) {
case 't':
if (strcmp(how, "tcp")) goto error;
nsock_connect_tcp(nsp, udata->nsiod, l_nsock_connect_handler,
udata->timeout, l, dest->ai_addr, dest->ai_addrlen, port);
break;
case 'u':
if (strcmp(how, "udp")) goto error;
nsock_connect_udp(nsp, udata->nsiod, l_nsock_connect_handler,
l, dest->ai_addr, dest->ai_addrlen, port);
break;
case 's':
if (strcmp(how, "ssl")) goto error;
#ifdef HAVE_OPENSSL
nsock_connect_ssl(nsp, udata->nsiod, l_nsock_connect_handler,
udata->timeout, l, dest->ai_addr, dest->ai_addrlen, port,
udata->ssl_session);
break;
#else
lua_pushboolean(l, false);
lua_pushstring(l, "Sorry, you don't have OpenSSL\n");
return 2;
#endif
default:
goto error;
break;
}
freeaddrinfo(dest);
return lua_yield(l, 0);
error:
freeaddrinfo(dest);
luaL_argerror(l, 4, "invalid connection method");
return 0;
}
void l_nsock_connect_handler(nsock_pool nsp, nsock_event nse, void *lua_state) {
lua_State* l = (lua_State*) lua_state;
if(o.scriptTrace()) {
l_nsock_trace(nse_iod(nse), "CONNECT", TO);
}
if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) {
process_waiting2running((lua_State*) lua_state, 1);
} else {
process_waiting2running((lua_State*) lua_state, 2);
}
}
static int l_nsock_send(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
const char* string = luaL_checkstring(l, 2);
size_t string_len = lua_objlen (l, 2);
char* hexified;
l_nsock_clear_buf(l,udata);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to send through a closed socket\n");
return 2;
}
if(o.scriptTrace()) {
hexified = nse_hexify((const void*)string, string_len);
l_nsock_trace(udata->nsiod, hexified, TO);
free(hexified);
}
nsock_write(nsp, udata->nsiod, l_nsock_send_handler, udata->timeout, l, string, string_len);
return lua_yield(l, 0);
}
void l_nsock_send_handler(nsock_pool nsp, nsock_event nse, void *lua_state) {
lua_State* l = (lua_State*) lua_state;
if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) {
process_waiting2running((lua_State*) lua_state, 1);
} else {
process_waiting2running((lua_State*) lua_state, 2);
}
}
static int l_nsock_receive(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
l_nsock_clear_buf(l, udata);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to receive through a closed socket\n");
return 2;
}
nsock_read(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout, l);
return lua_yield(l, 0);
}
static int l_nsock_receive_lines(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
int nlines = (int) luaL_checknumber(l, 2);
l_nsock_clear_buf(l, udata);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to receive lines through a closed socket\n");
return 2;
}
nsock_readlines(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout, l, nlines);
return lua_yield(l, 0);
}
static int l_nsock_receive_bytes(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
int nbytes = (int) luaL_checknumber(l, 2);
l_nsock_clear_buf(l, udata);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to receive bytes through a closed socket\n");
return 2;
}
nsock_readbytes(nsp, udata->nsiod, l_nsock_receive_handler, udata->timeout, l, nbytes);
return lua_yield(l, 0);
}
void l_nsock_receive_handler(nsock_pool nsp, nsock_event nse, void *lua_state) {
lua_State* l = (lua_State*) lua_state;
char* rcvd_string;
int rcvd_len = 0;
char* hexified;
if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) {
rcvd_string = nse_readbuf(nse, &rcvd_len);
if(o.scriptTrace()) {
hexified = nse_hexify((const void*) rcvd_string, (size_t) rcvd_len);
l_nsock_trace(nse_iod(nse), hexified, FROM);
free(hexified);
}
lua_pushlstring(l, rcvd_string, rcvd_len);
process_waiting2running((lua_State*) lua_state, 2);
} else {
process_waiting2running((lua_State*) lua_state, 2);
}
}
void l_nsock_trace(nsock_iod nsiod, const char* message, int direction) {
int status;
int protocol;
int af;
struct sockaddr local;
struct sockaddr remote;
char* ipstring_local = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
char* ipstring_remote = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
if(!nsi_is_pcap(nsiod)){
status = nsi_getlastcommunicationinfo(nsiod, &protocol, &af,
&local, &remote, sizeof(sockaddr));
log_write(LOG_STDOUT, "%s: %s %s:%d %s %s:%d | %s\n",
SCRIPT_ENGINE,
(protocol == IPPROTO_TCP)? "TCP" : "UDP",
inet_ntop_both(af, &local, ipstring_local),
inet_port_both(af, &local),
(direction == TO)? ">" : "<",
inet_ntop_both(af, &remote, ipstring_remote),
inet_port_both(af, &remote),
message);
free(ipstring_local);
free(ipstring_remote);
}else{ // is pcap device
log_write(LOG_STDOUT, "%s: %s | %s\n",
SCRIPT_ENGINE,
(direction == TO)? ">" : "<",
message);
}
}
const char* inet_ntop_both(int af, const void* v_addr, char* ipstring) {
// char* ipstring = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
if(af == AF_INET) {
inet_ntop(AF_INET, &((struct sockaddr_in*) v_addr)->sin_addr,
ipstring, INET6_ADDRSTRLEN);
return ipstring;
}
#ifdef HAVE_IPV6
else if(af == AF_INET6) {
inet_ntop(AF_INET6, &((struct sockaddr_in6*) v_addr)->sin6_addr,
ipstring, INET6_ADDRSTRLEN);
return ipstring;
}
#endif
else {
return "unknown protocol";
}
}
unsigned short inet_port_both(int af, const void* v_addr) {
int port;
if(af == AF_INET) {
port = ((struct sockaddr_in*) v_addr)->sin_port;
}
#ifdef HAVE_IPV6
else if(af == AF_INET6) {
port = ((struct sockaddr_in6*) v_addr)->sin6_port;
}
#endif
else {
port = 0;
}
return ntohs(port);
}
static int l_nsock_get_info(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
int status;
int protocol; // tcp or udp
int af; // address family
struct sockaddr local;
struct sockaddr remote;
char* ipstring_local = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
char* ipstring_remote = (char*) safe_malloc(sizeof(char) * INET6_ADDRSTRLEN);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to get info from a closed socket\n");
return 2;
}
status = nsi_getlastcommunicationinfo(udata->nsiod, &protocol, &af,
&local, &remote, sizeof(sockaddr));
lua_pushboolean(l, true);
lua_pushstring(l, inet_ntop_both(af, &local, ipstring_local));
lua_pushnumber(l, inet_port_both(af, &local));
lua_pushstring(l, inet_ntop_both(af, &remote, ipstring_remote));
lua_pushnumber(l, inet_port_both(af, &remote));
free(ipstring_local);
free(ipstring_remote);
return 5;
}
static int l_nsock_gc(lua_State* l){
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
if(udata->nsiod == NULL) { //socket obviously got closed already - so no finalization needed
return 0;
}else{
//FIXME - check wheter close returned true!!
l_nsock_close(l);
}
return 0;
}
static int l_nsock_close(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
/* Never ever collect nse-pcap connections. */
if(udata->ncap_socket){
return 0;
}
l_nsock_clear_buf(l, udata);
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to close a closed socket\n");
return 2;
}
if(o.scriptTrace()) {
l_nsock_trace(udata->nsiod, "CLOSE", TO);
}
#ifdef HAVE_OPENSSL
if (udata->ssl_session)
SSL_SESSION_free((SSL_SESSION*)udata->ssl_session);
udata->ssl_session=NULL;
#endif
nsi_delete(udata->nsiod, NSOCK_PENDING_NOTIFY);
nsock_descriptors_used--;
/* handle threads that are waiting for free sockets*/
if(nsock_connect_queue.size()){
lua_State *nl = nsock_connect_queue.front();
nsock_connect_queue.pop_front();
/* we can't restore lua thread here. instead create timer event with
* short timeout 0, and restore thread there*/
nsock_timer_create(nsp, l_nsock_connect_queued_handler, 0, (void*) nl);
}
udata->nsiod = NULL;
lua_pushboolean(l, true);
return 1;
}
static int l_nsock_set_timeout(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
int timeout = (unsigned short) luaL_checkint(l, 2);
udata->timeout = timeout;
return 0;
}
/* buffered I/O */
static int l_nsock_receive_buf(lua_State* l) {
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
if(lua_gettop(l)==2){
/*we were called with 2 arguments only - push the default third one*/
lua_pushboolean(l,true);
}
if(udata->nsiod == NULL) {
lua_pushboolean(l, false);
lua_pushstring(l, "Trying to receive through a closed socket\n");
return 2;
}
if(udata->bufused==0){
lua_pushstring(l,"");
udata->bufidx = luaL_ref(l, LUA_REGISTRYINDEX);
udata->bufused=1;
nsock_read(nsp, udata->nsiod, l_nsock_receive_buf_handler, udata->timeout, l);
}else if(udata->bufused==-1){ /*error message is inside the buffer*/
lua_pushboolean(l,false);
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx);
return 2;
}else{ /*buffer contains already some data */
/*we keep track here of how many calls to receive_buf are made */
udata->bufused++;
if(l_nsock_check_buf(l)==NSOCK_WRAPPER_BUFFER_MOREREAD){
/*if we didn't have enough data in the buffer another nsock_read()
* was scheduled - its callback will put us in running state again
*/
return lua_yield(l,3);
}
return 2;
}
/*yielding with 3 arguments since we need them when the callback arrives */
return lua_yield(l, 3);
}
void l_nsock_receive_buf_handler(nsock_pool nsp, nsock_event nse, void *lua_state) {
lua_State* l = (lua_State*) lua_state;
char* rcvd_string;
int rcvd_len = 0;
char* hexified;
int tmpidx;
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
if(l_nsock_checkstatus(l, nse) == NSOCK_WRAPPER_SUCCESS) {
//l_nsock_checkstatus pushes true on the stack in case of success
// we do this on our own here
lua_pop(l,1);
rcvd_string = nse_readbuf(nse, &rcvd_len);
if(o.scriptTrace()) {
hexified = nse_hexify((const void*) rcvd_string, (size_t) rcvd_len);
l_nsock_trace(nse_iod(nse), hexified, FROM);
free(hexified);
}
/* push the buffer and what we received from nsock on the stack and
* concatenate both*/
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx);
lua_pushlstring(l, rcvd_string, rcvd_len);
lua_concat (l, 2);
luaL_unref(l, LUA_REGISTRYINDEX, udata->bufidx);
udata->bufidx = luaL_ref(l, LUA_REGISTRYINDEX);
if(l_nsock_check_buf(l)==NSOCK_WRAPPER_BUFFER_MOREREAD){
/*if there wasn't enough data in the buffer and we've issued another
* nsock_read() the next callback will schedule the script for running
*/
return;
}
process_waiting2running((lua_State*) lua_state, 2);
} else {
if(udata->bufused>1){
/*error occured after we read into some data into the buffer
* behave as if there was no error and push the rest of the buffer
* and clean the buffer afterwards
*/
/*save the error message inside the buffer*/
tmpidx=luaL_ref(l, LUA_REGISTRYINDEX);
/*pop the status (==false) of the stack*/
lua_pop(l,1);
lua_pushboolean(l, true);
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx);
l_nsock_clear_buf(l, udata);
udata->bufidx=tmpidx;
udata->bufused=-1;
process_waiting2running((lua_State*) lua_state, 2);
}else{ /*buffer should be empty */
process_waiting2running((lua_State*) lua_state, 2);
}
}
}
int l_nsock_check_buf(lua_State* l ){
l_nsock_udata* udata;
size_t startpos, endpos, bufsize;
const char *tmpbuf;
int tmpidx;
int keeppattern;
/*should we return the string including the pattern or without it */
keeppattern= lua_toboolean(l,-1);
lua_pop(l,1);
udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
if(lua_isfunction(l,2)){
lua_pushvalue(l,2);
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx); /* the buffer is the only argument to the function */
if(lua_pcall(l,1,2,0)!=0){
lua_pushboolean(l,false);
lua_pushfstring(l,"Error inside splitting-function: %s\n", lua_tostring(l,-1));
return NSOCK_WRAPPER_BUFFER_OK;
//luaL_error(l,"Error inside splitting-function, given as argument to nsockobj:receive_buf: %s\n", lua_tostring(l,-1));
}
}else if(lua_isstring(l,2)){
lua_getglobal(l,"string");
lua_getfield(l,-1,"find");
lua_remove(l, -2); /*drop the string-table, since we don't need it! */
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx);
lua_pushvalue(l,2); /*the pattern we are searching for */
if(lua_pcall(l,2,2,0)!=0){
lua_pushboolean(l,false);
lua_pushstring(l,"Error in string.find (nsockobj:receive_buf)!");
return NSOCK_WRAPPER_BUFFER_OK;
}
}else{
lua_pushboolean(l,false);
lua_pushstring(l,"Expected either a function or a string!");
return NSOCK_WRAPPER_BUFFER_OK;
//luaL_argerror(l,2,"expected either a function or a string!");
}
/*the stack contains on top the indices where we want to seperate */
if(lua_isnil(l,-1)){ /*not found anything try to read more data*/
lua_pop(l,2);
nsock_read(nsp, udata->nsiod, l_nsock_receive_buf_handler, udata->timeout, l);
lua_pushboolean(l,keeppattern);
return NSOCK_WRAPPER_BUFFER_MOREREAD;
}else{
startpos = (size_t) lua_tointeger(l, -2);
endpos = (size_t) lua_tointeger(l, -1);
lua_settop(l,0); /* clear the stack for returning */
if(startpos>endpos){
lua_pushboolean(l,false);
lua_pushstring(l,"Delimiter has negative size!");
return NSOCK_WRAPPER_BUFFER_OK;
}else if(startpos==endpos){
/* if the delimter has a size of zero we keep it, since otherwise
* retured string would be trucated
*/
keeppattern=1;
}
lua_settop(l,0); /* clear the stack for returning */
lua_rawgeti(l, LUA_REGISTRYINDEX, udata->bufidx);
tmpbuf = lua_tolstring(l, -1, &bufsize);
lua_pop(l,1); /* pop the buffer off the stack, should be safe since it
it is still in the registry */
if(tmpbuf==NULL){
fatal("%s: In: %s:%i The buffer is not a string?! - please report this to nmap-dev@insecure.org.", SCRIPT_ENGINE, __FILE__, __LINE__);
}
/*first push the remains of the buffer */
lua_pushlstring(l,tmpbuf+endpos,(bufsize-endpos));
tmpidx = luaL_ref(l,LUA_REGISTRYINDEX);
lua_pushboolean(l,true);
if(keeppattern){
lua_pushlstring(l,tmpbuf,endpos);
}else{
lua_pushlstring(l,tmpbuf,startpos-1);
}
luaL_unref(l,LUA_REGISTRYINDEX,udata->bufidx);
udata->bufidx=tmpidx;
//l_dumpStack(l);
return NSOCK_WRAPPER_BUFFER_OK;
}
assert(0);
return 1;//unreachable
}
void l_nsock_clear_buf(lua_State* l, l_nsock_udata* udata){
luaL_unref (l, LUA_REGISTRYINDEX, udata->bufidx);
udata->bufidx=LUA_NOREF;
udata->bufused=0;
}
/****************** NCAP_SOCKET ***********************************************/
#ifdef WIN32
/* From tcpip.cc. Gets pcap device name from dnet name. */
bool DnetName2PcapName(const char *dnetdev, char *pcapdev, int pcapdevlen);
#endif
/* fuckin' C++ maps stuff */
/* here we store ncap_sockets */
std::map<std::string, struct ncap_socket*> ncap_socket_map;
/* receive sthing from socket_map */
struct ncap_socket *ncap_socket_map_get(char *key){
std::string skey = key;
return ncap_socket_map[skey];
}
/* set sthing on socket_map */
void ncap_socket_map_set(char *key, struct ncap_socket *ns){
std::string skey = key;
ncap_socket_map[skey] = ns;
return;
}
/* receive sthing from socket_map */
void ncap_socket_map_del(char *key){
std::string skey = key;
ncap_socket_map.erase(skey);
return;
}
/* (static) Dnet-like device name to Pcap-like name */
char *dnet_to_pcap_device_name(const char *device){
static char pcapdev[128];
if( strcmp(device, "any") == 0 )
return strncpy(pcapdev, "any", sizeof(pcapdev));
#ifdef WIN32
/* Nmap normally uses device names obtained through dnet for interfaces,
* but Pcap has its own naming system. So the conversion is done here */
if (!DnetName2PcapName(device, pcapdev, sizeof(pcapdev))) {
/* Oh crap -- couldn't find the corresponding dev apparently.
* Let's just go with what we have then ... */
strncpy(pcapdev, device, sizeof(pcapdev));
}
#else
strncpy(pcapdev, device, sizeof(pcapdev));
#endif
return pcapdev;
}
/* (LUA) Open nsock-pcap socket.
* 1) device - dnet-style network interface name, or "any"
* 2) snaplen - maximum number of bytes to be captured for packet
* 3) promisc - should we set network car in promiscuous mode (0/1)
* 4) callback- callback function, that will create hash string from packet
* 5) bpf - berkeley packet filter, see tcpdump(8)
* */
static int l_nsock_ncap_open(lua_State* l){
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
const char* device = luaL_checkstring(l, 2);
int snaplen = luaL_checkint(l, 3);
int promisc = luaL_checkint(l, 4);
luaL_checktype(l, 5, LUA_TFUNCTION); /* callback function that creates hash */
const char* bpf = luaL_checkstring(l, 6);
if(udata->nsiod || udata->ncap_request || udata->ncap_socket) {
luaL_argerror(l, 1, "Trying to open nsock-pcap, but this connection is already opened");
return 0;
}
char *pcapdev = dnet_to_pcap_device_name(device);
if(!strlen(device) || !strlen(pcapdev)) {
luaL_argerror(l, 1, "Trying to open nsock-pcap, but you're passing empty or wrong device name.");
return 0;
}
lua_pop(l, 1); // pop bpf
/* take func from top of stack and store it in the Registry */
int hash_func_ref = luaL_ref(l, LUA_REGISTRYINDEX);
/* push function on the registry-stack */
lua_rawgeti(l, LUA_REGISTRYINDEX, hash_func_ref);
struct ncap_socket *ns;
/* create key */
char key[8192];
Snprintf(key, sizeof(key), "%s|%i|%i|%u|%s",
pcapdev,
snaplen, promisc,
(unsigned int)strlen(bpf),
bpf);
ns = ncap_socket_map_get(key);
if(ns == NULL){
ns = (struct ncap_socket*)safe_zalloc(sizeof(struct ncap_socket));
ns->nsiod = nsi_new(nsp, ns);
ns->key = strdup(key);
/* error messages are passed here */
char *emsg = nsock_pcap_open(nsp, ns->nsiod, pcapdev, snaplen, promisc, bpf);
if(emsg){
luaL_argerror(l, 1, emsg);
return 0;
}
ncap_socket_map_set(key, ns);
}
ns->references++;
udata->nsiod = ns->nsiod;
udata->ncap_socket = ns;
udata->ncap_cback_ref = hash_func_ref;
return 0;
}
/* (LUA) Close nsock-pcap socket.
* */
static int l_nsock_ncap_close(lua_State* l){
l_nsock_udata* udata = (l_nsock_udata*) auxiliar_checkclass(l, "nsock", 1);
struct ncap_socket *ns = udata->ncap_socket;
if(!udata->nsiod || !udata->ncap_socket) {
luaL_argerror(l, 1, "Trying to close nsock-pcap, but it was never opened.");
return 0;
}
if(udata->ncap_request) {
luaL_argerror(l, 1, "Trying to close nsock-pcap, but it has active event.");
return 0;
}
assert(ns->references > 0);
ns->references--;
if(ns->references == 0){
ncap_socket_map_del(ns->key);
if(ns->key) free(ns->key);
nsi_delete(ns->nsiod, NSOCK_PENDING_NOTIFY);
free(ns);
}
udata->nsiod = NULL;
udata->ncap_socket = NULL;
lua_unref(l, udata->ncap_cback_ref);
udata->ncap_cback_ref = 0;
lua_pushboolean(l, true);
return 1;
}
/* (static) binary string to hex zero-terminated string */
char *hex(char *str, unsigned int strsz){
static char x[] = {'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
static char buf[2048];
unsigned int i;
unsigned char *s;
for(i=0, s=(unsigned char*)str; i<strsz && i<(sizeof(buf)/2-1); i++, s++){
buf[i*2 ] = x[ *s/16 ];
buf[i*2+1] = x[ *s%16 ];
}
buf[i*2] = '\0';
return(buf);
}
/****************** NCAP_REQUEST **********************************************/
int ncap_restore_lua(ncap_request *nr);
void ncap_request_set_result(nsock_event nse, struct ncap_request *nr);
int ncap_request_set_results(nsock_event nse, const char *key);
void l_nsock_pcap_receive_handler(nsock_pool nsp, nsock_event nse, void *userdata);
/* next map, this time it's multimap "key"(from callback)->suspended_lua_threads */
std::multimap<std::string, struct ncap_request*> ncap_request_map;
typedef std::multimap<std::string, struct ncap_request*>::iterator ncap_request_map_iterator;
typedef std::pair<ncap_request_map_iterator, ncap_request_map_iterator> ncap_request_map_ii;
/* del from multimap */
void ncap_request_map_del(struct ncap_request *nr){
ncap_request_map_iterator i;
ncap_request_map_ii ii;
std::string s = nr->key;
ii = ncap_request_map.equal_range(s);
for(i=ii.first ; i!=ii.second ;i++){
if(i->second == nr){
i->second = NULL;
ncap_request_map.erase(i);
return;
}
}
assert(0);
}
/* add to multimap */
void ncap_request_map_add(char *key, struct ncap_request *nr){
std::string skey = key;
ncap_request_map.insert(std::pair<std::string, struct ncap_request *>(skey, nr));
return;
}