Nmap Development mailing list archives

Tudor's Status Report - #9 of #17


From: Tudor-Emil COMAN <tudor_emil.coman () cti pub ro>
Date: Mon, 4 Jul 2016 22:52:39 +0000

Hello,



I spent the past week finishing up and polishing the IOCP engine for Nsock.

I've made a branch in my directory in nmap-exp: https://svn.nmap.org/nmap-exp/tudor/nsock-iocp/



Brandon has advised me watch out for and test some key particular cases.


SSL:

In order to test SSL I used the following command:

# nmap.exe -p 443 -v -d -Pn -n -T5 --script=ssl-cert www.citibank.com --nsock-engine=iocp
And it works the same as the other engines.

UDP:
There was a problem with UDP from the ConnectEx function.
The DNS reverse lookup wasn't working and after pinpointing that the problem was with ConnectEx I went back to the 
documentation and found that:
The ConnectEx function is only supported on connection-oriented sockets.
After seeing that, I went back and used the lastproto member of the niod structure to decide whether to use connect(if 
lastproto is not IPPROTO_TCP) or ConnectEx otherwise.
This seems to have solved the DNS reverse lookup problem.

IPv6 scanning seems to work.

PPP fails with:
Only ethernet devices can be used for raw scans on Windows, and
"ppp0" is not an ethernet device. Use the --unprivileged option'
This is probably from a safeguard somewhere but I didn't have time to search for it and disable it.

Localhost scanning shows all ports marked as unknown.



One of the concerns regarding adding another engine was that it would add more complexity to Nsock in general and make 
the code more hard to read.

There was quite a bit of code that was pilling up in nsock_core.c so I took all that code from there and added it to a 
new file that I named nsock_iocp.c with a nsock_iocp.h to be included by other files.


From nsock_core only 3 functions are called from that file:

initiate_overlapped_event() (2 times)

terminate_overlapped_event() (1 time)

get_overlapped_result() (3 times)


 - initiate_overlapped_event() needs to be called every single time an event needs to perform an action on a socket. So 
it is called both when an event is associated with a socket and when the event was processed but not finished.

 - terminate_overlapped_event() needs to be called when the event associated with the overlapped operation has expired.

 - get_overlapped_result() has to be called to get the results of the previously initiated overlapped event. This will 
replace the send and recv functions from the read and write handlers but it will also be called from the connect 
handler to get the error (if an error has occurred).


Two lists were also added in the npool structure to keep track of the extended_overlapped buffers and recycle them in 
the same way nevents and niods recycled.

One big problem engine IOCP has is that it uses a lot of memory. Not only because one special structure needs to be 
made for each little read/write/connect that happens, for the read event, a read buffer 8192 bytes in size(to mirror 
the one in do_actual_read) has to be allocated and kept for each read operation at one moment in time.  Even though it 
happened rarely and in extreme testing conditions (parallelism level > 2000, hostgroup > 5000) I did loose some scans 
because Nmap would run out of memory and exit.


In nsock_iocp.h there is also a free_eov exposed that is used by engine_iocp.c


So that's about the extent of the added complexity.


One more important thing is that in nbase_misc the socket is created with the WSA_FLAG_OVERLAPPED which is rather 
harmless because such a socket supports non-overlapped operations just as well, it just *enables* overlapped. Even the 
Microsoft documentations states that:

Most sockets should be created with this flag set.

https://msdn.microsoft.com/en-us/library/windows/desktop/ms742212(v=vs.85).aspx



HAVE_IOCP is defined always alongside HAVE_POLL. The official Microsoft documentation says that most of the function 
calls that I used like ConnectEx, GetQueuedCompletionStatusEx, WSARecv are only available after Vista. Some people said 
that these functions can be found Windows XP too and they probably are but I don't think it's a good idea to use them 
especially if we drop support for Windows XP anyway. Also I gave the engine a lower priority than poll so it should be 
called explicitly with the --nsock-engine=iocp parameter.


I also added another engine comparison. Last week's scans were bad because I didn't handle the expired events well but 
now that's fixed and the results make more sense.

For the scans in these graphs I also disabled NSE for service scanning.




I also took a peek into those old registry tweaks.

 - MaxUserPort: https://support.microsoft.com/en-us/kb/196271

  So the problem with this one as I understood it was that if a connect would bind the local address to a source port 
higher than 5000, it would fail with WSAENOBUFS.

  It's fairly simple to test out, just before issuing the connect() call I bind that socket on ports higher that 5000. 
I use a static variable in connect_internal that starts at 5000, the value is used to bind the socket and it is then 
incremented for the next call.

  I tested it on Windows Vista Ultimate 64-bit(in a VM) and Windows 7 Professional 32-bit(in a VM) with a service scan 
and the bind never failed.

Nmap was compiled from source so those registry tweaks weren't issued by the installer or anything.


- TcpTimedWaitDelay: https://support.microsoft.com/en-us/kb/149532

 I don't really see the problem here to be honest. You get less active connections than your port range because some of 
those ports will be caught up in the TimeWait state after a TCP connection ended. The TcpTimedWaitDelay default value 
is 240 seconds and  we reduce the amount of time we have to wait for these ports to linger to 30 seconds so it is 
better in a way to have this.


- StrictTimeWaitSeqCheck needs to be set to 1 in order for TcpTimedWaitDelay to take effect.


The MaxUserPort entry increases the default range of the ports used for outgoing connections all the way up from 5000 
to 65534 thus removing a pointless connection cap.


I don't think we should remove these registry entries.





Accomplishments:

- Switched from GetQueuedCompletionStatus to GetQueuedCompletionStatusEx and identified and fixed a bug with the latter 
function.

- Added lists to the pool structure that should track the usage of extended_overlapped structures to make sure no 
memory leaks occur and also recycle what it can for future use.

- Finally made a SVN branch.

- Restructured the code, moved a lot of it into separate files.

- Investigated the registry tweaks.


Priorities:

- See what could be improved.

- Take another look at the tftp-enum script.

- Make some really cool engine_iocp stats.




Any thoughts?

Tudor


_______________________________________________
Sent through the dev mailing list
https://nmap.org/mailman/listinfo/dev
Archived at http://seclists.org/nmap-dev/

Current thread: